OpenID Connect on top of OAuth 2.0 is the dominant federated identity protocol for modern stacks. Every major enterprise IdP supports it; every cloud workforce IdP exposes it; every modern application framework offers a library for it. The temptation is to assume that adding a few lines of SDK code per application is enough.
In practice, an OIDC relying party that handles real production traffic must do a long list of things correctly. The ID token's signature must be verified against the IdP's published JWKS, with the correct key selected by kid and the cache refreshed when the IdP rotates keys. The audience claim must match the configured client ID. The issuer must match the configured expected issuer. The expiry must be checked with a bounded clock-skew tolerance. The nonce in the ID token must match the nonce AAM sent in the authorization request — and if it doesn't, that's a replay attempt, not a parsing error.
The OAuth 2.0 layer underneath has its own footguns. State must be CSRF-bound to the user's session and have a short TTL. PKCE must be used (S256 ideally) so an intercepted authorization code cannot be redeemed by an attacker. Mixup attacks — where an attacker tricks the relying party into talking to the wrong IdP — are defeated by binding the callback to a specific IdP and validating issuer accordingly. None of these defenses are automatic in a naïve SDK integration.
The other failure mode is embedding the OIDC SDK directly into every application. Each app then carries its own copy of the trust decisions, the JWKS cache, the audit logging, and the IdP configuration. A single IdP change becomes a coordinated multi-application rollout. MFA, conditional access, posture, and logout behaviour end up re-solved per application, often inconsistently.
OIDC belongs at the access edge — verified once, correctly, in one place that already runs MFA, conditional access, posture, and Backend SSO. The application stays out of the federation protocol and receives a clean, validated identity instead.
One AAM gateway terminates OIDC correctly at the edge; the rest of the access engine composes on top.
Authorization code flow with PKCE, ID token signature verification via JWKS, nonce-bound replay defense, state-bound CSRF defense, audience/issuer/validity enforcement. The same engine speaks plain OAuth 2.0 for IdPs that don't expose an ID token, so token-only providers and full OIDC providers share one codebase.
One AAM gateway can route different applications to different IdPs, and different tenants of the same application to different IdPs, at the same time. IdP selection happens per request from the application or tenant context — no separate gateway per IdP, no manual chooser for the user.
Nonce binds the ID token to the authorization request that asked for it; state binds the callback to the user's session; PKCE binds the code redemption to the original public client. None of these are optional flags that an integrator can forget — they are the default flow.
An OIDC authentication does not stand alone — it composes with edge MFA (if the IdP didn't enforce step-up itself), with conditional access predicates, with continuous trust evaluation, and with Backend SSO injection toward the downstream app. The ID token becomes one input into the AAM session, not the whole session.
Standards-correct OIDC relying party plus the operational features that make federation safe and manageable at scale.
AAM initiates the OAuth 2.0 authorization code flow with PKCE enabled by default — code_challenge_method=S256, a fresh code_verifier per request, never reused. An intercepted authorization code cannot be exchanged for tokens by an attacker that didn't generate the verifier. Plain PKCE remains available for IdPs that demand it; S256 is the configured default.
On callback, AAM fetches the IdP's JWKS, selects the signing key by the ID token's kid header, and verifies the ID token's signature with the algorithm declared in the header (RS256 and the rest of the standard family). A cache miss on kid triggers an immediate JWKS refresh so an IdP key rotation does not stall valid logins.
The ID token's audience claim must include the configured client ID, the issuer must match the configured expected issuer, the validity window (exp/nbf) is enforced with a bounded clock-skew tolerance, and the nonce must match the nonce AAM sent in the authorization request. A nonce mismatch is treated as a replay-attack signal with its own audit event, not as a parsing error.
JWKS responses are cached in a shared store across worker processes and gateway instances with a 1-hour TTL. A cache hit avoids the network round-trip on every login; a cache miss on the requested kid triggers an immediate refresh from the JWKS URI so a routine IdP key rotation does not produce a login outage.
Standard OIDC authorization parameters are first-class configuration: scope (openid auto-added), display for the IdP login UX, max_age for forced re-authentication, ui_locales for localised IdP pages, and acr_values for requesting a specific authentication context class — useful for asking the IdP to enforce step-up MFA.
Built-in profiles ship with sensible defaults for common providers (well-known endpoints, JWKS URIs, scope conventions). A custom-IdP path remains for any standards-compliant OIDC or OAuth 2.0 provider that needs endpoints, scopes, and mappings supplied explicitly.
After signature verification, the ID token's claims are merged with the response from the IdP's userinfo endpoint. Signed ID token claims take precedence over unsigned userinfo fields where they overlap, so an attacker who tampered with a userinfo response cannot quietly override a signed identity claim.
RP-Initiated Logout (the OIDC spec's signed front-channel logout) and back-channel logout for session termination notifications from the IdP are on the roadmap. OIDC dynamic client registration — onboarding a new application by registering with the IdP automatically — is also planned. The session and audit plumbing already accommodate these flows.
The mechanics that keep an OIDC federation safe, current, and observable.
The OAuth state parameter is stored against the user's session with a 10-minute TTL. On callback, AAM verifies the state belongs to the same session that initiated the flow — an attacker who replays a state value into another user's browser is rejected with an OAUTH_STATE_MISMATCH audit event.
When ID token signature verification is skipped for any operational reason — JWKS unavailable, no matching kid, malformed JWK, missing JWKS URI — a dedicated audit event records the specific leaf cause. Operators can distinguish a transient JWKS outage from a misconfiguration from an unsupported key type without re-reading runtime logs.
ID tokens carry iat, nbf, and exp timestamps. Real clocks drift; AAM applies a bounded clock-skew tolerance (60 seconds by default for the underlying JWT verifier) so small drift does not reject valid logins while large drift — which indicates misconfiguration or replay — still rejects.
Token exchange and userinfo requests against the IdP use bounded connect, DNS, and overall timeouts so a slow or unresponsive IdP cannot tie up gateway workers. Token exchange runs on a 30-second overall budget; userinfo runs on a 15-second budget; both have shorter connect and DNS budgets so failures fail fast.
Every step of the OIDC flow — flow start, callback success, token exchange (with which tokens were returned), ID token signature verification outcome, JWKS fetch outcome — is recorded with a correlation ID that ties back to the AAM session and the downstream backend(s). Forensic reconstruction of "who signed in via which IdP and when" is a single-query operation.
Automated OIDC provider discovery via the .well-known/openid-configuration endpoint, with operator alerting when discovered endpoints or signing-key sets change, is on the roadmap. JWKS rotation telemetry — metrics on signing-key churn, days-until-current-key-expiry hints, automated rotation runbooks — is also planned.
Existing enterprise IdPs that already authenticate the workforce over OIDC. AAM plugs in as a relying party without asking the IdP team to change anything. New applications join the federation by adding an entry to AAM, not by adding an OIDC SDK to each codebase.
Internal tooling that authenticates against the organisation's Google Workspace tenant, or developer tooling that uses GitHub as the IdP. AAM speaks OIDC to Google and OAuth 2.0 to GitHub from the same engine, mapping each into the canonical AAM session shape.
SaaS applications where each customer brings their own OIDC IdP. One AAM gateway fronts all tenants; each tenant's traffic routes to that tenant's IdP. Adding a tenant is a configuration change in the IdP registry, not a deploy.
Some IdPs authenticate but don't enforce step-up MFA or conditional access for every application equally. AAM accepts the IdP's authentication, then composes its own MFA, conditional access predicates, and continuous trust evaluation on top before granting access to the application.
We'll connect AAM to your OIDC IdP — enterprise, cloud, or self-hosted — and let the rest of the access engine compose MFA, conditional access, posture, and Backend SSO on top of the verified ID token.