Verify OpenID Connect ID Tokens issued by an authorization server.
This is the client-side mirror of Attesto.IDToken.mint/4. A relying party
receives an ID Token from the server, fetches (or supplies) the server JWKS,
and verifies the signed JWT plus the OIDC claims that bind it to the client
and the authorization response.
Checks
- signature verifies against the issuer JWKS, selected by
kid, with Attesto's supported asymmetric algorithms. - JOSE
typ, when present, must be"JWT"; an access-token type such as"at+jwt"is rejected. issequals:issuer.audequals, or is an all-string array containing,:client_id.azpequals:client_idwhenever present, and is required whenaudcontains multiple audiences.sub,exp, andiatare present and well-typed;expmust be in the future andiatmust not be meaningfully in the future.- a supplied
:noncemust match the token'snonceclaim. auth_time, when present, must not be meaningfully in the future; a supplied:max_agerequiresauth_timeand enforces the age.- supplied
:access_token,:code, and:stateare checked againstat_hash,c_hash, ands_hashrespectively using the ID Token signing algorithm's left-half hash construction.
:jwks may be supplied directly. Otherwise the verifier can fetch through
AttestoClient.Discovery: pass :metadata, :jwks_uri, or just :issuer
with optional :req_options / :well_known.
Unsigned ID Tokens (alg: "none")
By default an unsigned ID Token is rejected. OIDC Core §3.1.3.7 permits a
client to skip signature validation only when the ID Token was received
directly from the token endpoint over TLS and the client registered
id_token_signed_response_alg none. Pass allow_unsigned: true to opt
into that case: a token whose JOSE header alg is exactly "none" (with an
empty signature part) is then accepted without signature verification, while
all claim checks still run. The option has no effect on signed tokens,
and never applies to artifacts received through the front channel.
Summary
Functions
Verify id_token, returning {:ok, claims} or {:error, reason}.
Types
@type error() :: :missing_issuer | :missing_client_id | :invalid_jwks | :invalid_metadata | :issuer_mismatch | :unsupported_alg | :invalid_token | :invalid_signature | :unsupported_critical_header | :unexpected_typ | :invalid_issuer | :invalid_audience | :missing_azp | :invalid_azp | :invalid_claims | :missing_exp | :expired | :invalid_iat | :not_yet_valid | :nonce_required | :nonce_mismatch | :invalid_max_age | :auth_time_required | :invalid_auth_time | :max_age_exceeded | :missing_at_hash | :invalid_at_hash | :missing_c_hash | :invalid_c_hash | :missing_s_hash | :invalid_s_hash | AttestoClient.Discovery.error()
@type verify_opt() :: {:issuer, String.t()} | {:client_id, String.t()} | {:jwks, jwks()} | {:metadata, map()} | {:jwks_uri, String.t()} | {:nonce, String.t()} | {:max_age, non_neg_integer()} | {:access_token, String.t()} | {:code, String.t()} | {:state, String.t()} | {:accepted_algs, [Attesto.SigningAlg.alg()]} | {:allow_unsigned, boolean()} | {:now, integer() | DateTime.t()} | {:req_options, keyword()} | {:well_known, AttestoClient.Discovery.well_known()}
Functions
@spec verify(String.t(), [verify_opt()]) :: {:ok, map()} | {:error, error()}
Verify id_token, returning {:ok, claims} or {:error, reason}.
Required options:
:issuer- expected OpenID Provider issuer.:client_id- this relying party's client id.
JWKS options:
:jwks- a JWKS map/list supplied by the caller.:metadata- discovery metadata containing matchingissuerandjwks_uri.:jwks_uri- fetch only the JWKS.- no JWKS option - fetch discovery from
:issuer, then fetch its JWKS.