Skip to content

Commit 02f021a

Browse files
committed
Verify ID token before using as logout hint
Add verifyIdToken() function to validate ID tokens with full OIDC-compliant checks (signature, issuer, expiration, audience) before passing to IdP. If verification fails during logout, proceed without the id_token_hint parameter rather than sending an unverified token.
1 parent 0089cbb commit 02f021a

2 files changed

Lines changed: 28 additions & 2 deletions

File tree

src/lib/server/oidc.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,17 @@ export async function verify(
130130
}
131131
}
132132

133+
/**
134+
* Verify an ID token with full OIDC-compliant validation (signature, issuer, expiration, audience).
135+
*
136+
* @param idToken - The raw ID token string to verify
137+
* @returns The decoded JWT payload if verification is successful
138+
* @throws {Error} If the token is invalid, expired, or fails audience validation
139+
*/
140+
export async function verifyIdToken(idToken: string): Promise<MaybeToken> {
141+
return verify(idToken, DEFAULT_JWKS_CLIENT, ID_TOKEN_VERIFY_OPTS);
142+
}
143+
133144
/**
134145
* Verify that the nonce in an ID token matches the expected nonce.
135146
* This prevents replay attacks where an attacker reuses a previously issued ID token.

src/routes/oidc/logout/+server.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,20 @@ export const GET = async ({ cookies }) => {
1313
console.debug('/oidc/logout (GET)');
1414

1515
const client = await auth.Client.instance;
16-
const idToken = cookies.get('idToken') ?? '';
16+
const idToken = cookies.get('idToken');
17+
18+
// Verify the ID token before using it as a hint to the IdP.
19+
// If verification fails, we still proceed with logout but without the hint.
20+
let verifiedIdToken: string | undefined;
21+
if (idToken) {
22+
try {
23+
await auth.verifyIdToken(idToken);
24+
verifiedIdToken = idToken;
25+
} catch {
26+
// Token invalid or expired - proceed without hint
27+
console.debug('ID token verification failed during logout, proceeding without id_token_hint');
28+
}
29+
}
1730

1831
// delete cookies here
1932
cookies.delete('accessToken', { path: '/' });
@@ -26,7 +39,9 @@ export const GET = async ({ cookies }) => {
2639
const logoutUrl = new URL(client.getLogoutEndpoint());
2740

2841
logoutUrl.searchParams.set('post_logout_redirect_uri', `${ORIGIN}`);
29-
logoutUrl.searchParams.set('id_token_hint', idToken);
42+
if (verifiedIdToken) {
43+
logoutUrl.searchParams.set('id_token_hint', verifiedIdToken);
44+
}
3045

3146
// redirect to the logout endpoint
3247
redirect(302, logoutUrl.toString());

0 commit comments

Comments
 (0)