/** * Typed failure modes of the OIDC callback. The controller maps each * to a query-param identifier on the SPA redirect so the front-end * can render an appropriate message without inventing strings. * * Keep this list flat — the controller's `switch` is exhaustive * thanks to TypeScript's narrowing on `kind`. */ export type AuthCodeFlowError = | { kind: 'state-mismatch' } | { kind: 'flow-expired' } | { kind: 'token-exchange-failed'; cause: string }; export class AuthCodeFlowException extends Error { constructor(readonly failure: AuthCodeFlowError) { super(`auth code flow failed: ${failure.kind}`); this.name = 'AuthCodeFlowException'; } } /** * Stable short codes used as `?auth_error=` on the SPA-bound * redirect. Same identifiers as the discriminant `kind` so log * grepping correlates trivially. */ export function authErrorCode(failure: AuthCodeFlowError): string { return failure.kind; }