OIDC
OIDC at the Askr server boundary, with validated input and explicit failure states.
Example
Use discovery and authorization-code flow helpers at the server boundary; validate state, nonce, redirect URI, and issuer on callback.
import { createOidcClient } from '@askrjs/auth/oidc';
const oidc = await createOidcClient({
issuer: env.OIDC_ISSUER,
clientId: env.OIDC_CLIENT_ID,
redirectUri: env.OIDC_REDIRECT_URI,
});Discovery
createOidcClient(options: OidcClientOptions) takes issuer, clientId, an optional clientSecret, redirectUri, scopes, and an injectable fetch, and returns an OidcClient. Its discover() method fetches the provider's OidcProviderMetadata - authorization_endpoint, token_endpoint, jwks_uri, and the optional userinfo_endpoint and end_session_endpoint - so you don't hardcode those URLs per provider.
Authorization flow
createAuthorizationRequest(options?: {state?, nonce?, codeVerifier?, loginHint?}) builds the redirect URL for the provider's authorization endpoint and returns it alongside the state, nonce, and PKCE codeVerifier it used - generating any of the three for you if you don't supply them. The caller's only job is to persist those values (typically in a short-lived cookie) so they're available when the browser comes back to the callback route.
Callback validation
Once the browser returns with a code, exchangeCode({code, state, request: {state, nonce, codeVerifier}}) posts to the provider's token endpoint and resolves to { tokens, principal } - it already validates the ID token internally (signature, issuer, audience, and the nonce you stored earlier) as part of the exchange, rejecting with an OidcClientError('invalid-id-token', ...) if any of those checks fail. There's no separate validateOidcIdToken() call to make on this path; that function exists for validating an ID token you obtained some other way, not as a required second step after exchangeCode().
Session establishment
Neither createOidcClient nor validateOidcIdToken create an application session - that's left to you deliberately, since how you store sessions is covered under Model and Sessions. After the code exchange and ID token check succeed, a callback handler typically creates a SessionStore entry or issues your own JWT via createJwtIssuer, then sets a cookie with @askrjs/server's ctx.setCookie(), the same way the framework's built-in auth routes do.