/** * OIDC End Session Endpoint * * Handles /oauth/end_session - RP-initiated logout */ import { Router, Request, Response } from 'express'; import type { DatabaseService } from '../../services/database.js'; import type { OIDCService } from '../../services/oidc/index.js'; export function createLogoutRouter(db: DatabaseService, oidcService: OIDCService): Router { const router = Router(); /** * GET /oauth/end_session * RP-initiated logout */ router.get('/end_session', async (req: Request, res: Response) => { try { const { id_token_hint, client_id, post_logout_redirect_uri, state, } = req.query as { id_token_hint?: string; client_id?: string; post_logout_redirect_uri?: string; state?: string; }; let sub: string | undefined; let tokenClientId: string | undefined; // Verify id_token_hint if provided if (id_token_hint) { const claims = oidcService.tokenService.verifyIdToken(id_token_hint); if (claims) { sub = claims.sub; tokenClientId = claims.aud; } } // Use client_id from token or parameter const effectiveClientId = client_id || tokenClientId; // Validate post_logout_redirect_uri if provided if (post_logout_redirect_uri && effectiveClientId) { const client = db.getOIDCClient(effectiveClientId); if (!client) { return res.status(400).json({ error: 'invalid_request', error_description: 'Unknown client', }); } // Check if redirect URI origin matches a registered redirect_uri origin let redirectAllowed = false; try { const redirectOrigin = new URL(post_logout_redirect_uri).origin; redirectAllowed = client.redirect_uris.some((uri) => { try { return new URL(uri).origin === redirectOrigin; } catch { return false; } }); } catch { /* invalid URL */ } if (!redirectAllowed) { return res.status(400).json({ error: 'invalid_request', error_description: 'Invalid post_logout_redirect_uri', }); } } // Revoke all refresh tokens for this user and client if (sub && effectiveClientId) { db.revokeAllRefreshTokensForUser(sub, effectiveClientId); } // If we have a post_logout_redirect_uri, redirect there if (post_logout_redirect_uri) { const redirectUrl = new URL(post_logout_redirect_uri); if (state) { redirectUrl.searchParams.set('state', state); } return res.redirect(redirectUrl.toString()); } // Otherwise, show a logged out page res.send(`
You have been successfully logged out.