fix(encryptid): show success page instead of auto-OIDC redirect
The auto-redirect through OIDC authorize fails because the client app (Postiz) didn't initiate the OAuth flow and has no matching state. Instead, show a branded success page with a link to the app. The user signs in with their passkey when they visit the app normally. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d861c0ad99
commit
8723aae3f6
|
|
@ -4165,11 +4165,16 @@ app.get('/api/invites/identity/:token/info', async (c) => {
|
|||
if (Date.now() > invite.expiresAt) {
|
||||
return c.json({ error: 'Invite expired' }, 410);
|
||||
}
|
||||
// Look up OIDC client name if this is a client invite
|
||||
// Look up OIDC client info if this is a client invite
|
||||
let clientName: string | null = null;
|
||||
let clientAppUrl: string | null = null;
|
||||
if (invite.clientId) {
|
||||
const client = await getOidcClient(invite.clientId);
|
||||
clientName = client?.name || null;
|
||||
// Derive app URL from first redirect URI (strip the callback path)
|
||||
if (client?.redirectUris?.[0]) {
|
||||
try { clientAppUrl = new URL(client.redirectUris[0]).origin; } catch {}
|
||||
}
|
||||
}
|
||||
return c.json({
|
||||
invitedBy: invite.invitedByUsername,
|
||||
|
|
@ -4178,6 +4183,7 @@ app.get('/api/invites/identity/:token/info', async (c) => {
|
|||
spaceSlug: invite.spaceSlug,
|
||||
clientId: invite.clientId,
|
||||
clientName,
|
||||
clientAppUrl,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -4774,24 +4780,23 @@ function oidcAcceptPage(token: string): string {
|
|||
return;
|
||||
}
|
||||
|
||||
// If this is an OIDC client invite, redirect through the OIDC authorize flow
|
||||
if (inviteData.clientId) {
|
||||
showStatus('Redirecting to ' + (inviteData.clientName || 'the app') + '...');
|
||||
// Store the session token so the OIDC authorize page can use it
|
||||
localStorage.setItem('eid_token', sessionToken);
|
||||
// Start the OIDC authorize flow — the authorize page will auto-login
|
||||
window.location.href = '/oidc/authorize?client_id=' + encodeURIComponent(inviteData.clientId) +
|
||||
'&response_type=code&scope=openid+profile+email&redirect_uri=' + encodeURIComponent('auto') +
|
||||
'&state=invite_accept';
|
||||
return;
|
||||
}
|
||||
|
||||
// Non-OIDC invite — show success
|
||||
// Show success with link to the app
|
||||
document.getElementById('authSection').style.display = 'none';
|
||||
statusEl.style.display = 'none';
|
||||
successEl.innerHTML = '<strong>Welcome!</strong><br>Your invitation has been accepted.' +
|
||||
(claimData.spaceSlug ? '<br>You\\'ve been added to <strong>' + esc(claimData.spaceSlug) + '</strong>.' : '') +
|
||||
'<br><br><a href="https://rspace.online" style="color: #7c3aed;">Go to rSpace \\u2192</a>';
|
||||
|
||||
const appName = inviteData.clientName || 'rSpace';
|
||||
const appUrl = inviteData.clientAppUrl || 'https://rspace.online';
|
||||
|
||||
if (inviteData.clientId) {
|
||||
successEl.innerHTML = '<strong>You\\u2019re in!</strong><br>' +
|
||||
'Your account is set up and you\\u2019ve been granted access to <strong>' + esc(appName) + '</strong>.' +
|
||||
'<br><br><a href="' + esc(appUrl) + '" style="display:inline-block;padding:0.7rem 1.5rem;background:linear-gradient(90deg,#00d4ff,#7c3aed);color:#fff;text-decoration:none;border-radius:0.5rem;font-weight:600;">Go to ' + esc(appName) + ' \\u2192</a>' +
|
||||
'<p style="color:#94a3b8;font-size:0.8rem;margin-top:1rem;">You\\u2019ll sign in with your passkey when you get there.</p>';
|
||||
} else {
|
||||
successEl.innerHTML = '<strong>Welcome!</strong><br>Your invitation has been accepted.' +
|
||||
(claimData.spaceSlug ? '<br>You\\u2019ve been added to <strong>' + esc(claimData.spaceSlug) + '</strong>.' : '') +
|
||||
'<br><br><a href="https://rspace.online" style="color: #7c3aed;">Go to rSpace \\u2192</a>';
|
||||
}
|
||||
successEl.style.display = 'block';
|
||||
}
|
||||
|
||||
|
|
@ -4946,7 +4951,7 @@ app.get('/.well-known/openid-configuration', (c) => {
|
|||
// Authorization endpoint
|
||||
app.get('/oidc/authorize', async (c) => {
|
||||
const clientId = c.req.query('client_id');
|
||||
let redirectUri = c.req.query('redirect_uri');
|
||||
const redirectUri = c.req.query('redirect_uri');
|
||||
const responseType = c.req.query('response_type');
|
||||
const scope = c.req.query('scope') || 'openid profile email';
|
||||
const state = c.req.query('state') || '';
|
||||
|
|
@ -4963,11 +4968,6 @@ app.get('/oidc/authorize', async (c) => {
|
|||
return c.text('Unknown client_id', 400);
|
||||
}
|
||||
|
||||
// "auto" redirect_uri: use the client's first registered redirect URI (from invite accept flow)
|
||||
if (redirectUri === 'auto') {
|
||||
redirectUri = client.redirectUris[0];
|
||||
}
|
||||
|
||||
if (!client.redirectUris.includes(redirectUri)) {
|
||||
return c.text('Invalid redirect_uri', 400);
|
||||
}
|
||||
|
|
@ -5353,39 +5353,6 @@ function oidcAuthorizePage(appName: string, clientId: string, redirectUri: strin
|
|||
}
|
||||
}
|
||||
|
||||
// Auto-authorize if coming from invite accept flow with a stored session token
|
||||
(async () => {
|
||||
if (STATE !== 'invite_accept') return;
|
||||
const storedToken = localStorage.getItem('eid_token');
|
||||
if (!storedToken) return;
|
||||
localStorage.removeItem('eid_token');
|
||||
loginBtn.disabled = true;
|
||||
showStatus('Authorizing...');
|
||||
try {
|
||||
const authorizeRes = await fetch('/oidc/authorize', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
clientId: CLIENT_ID,
|
||||
redirectUri: REDIRECT_URI,
|
||||
scope: SCOPE,
|
||||
state: STATE,
|
||||
token: storedToken,
|
||||
}),
|
||||
});
|
||||
const authorizeResult = await authorizeRes.json();
|
||||
if (authorizeResult.error) {
|
||||
showError(authorizeResult.message || authorizeResult.error);
|
||||
loginBtn.disabled = false;
|
||||
return;
|
||||
}
|
||||
showStatus('Redirecting...');
|
||||
window.location.href = authorizeResult.redirectUrl;
|
||||
} catch (err) {
|
||||
showError('Auto-login failed. Please sign in manually.');
|
||||
loginBtn.disabled = false;
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
|
|
|||
Loading…
Reference in New Issue