SIOPv2 Self-Issued ID Token verification for the Relying Party role.
A Self-Issued ID Token is not verified against an issuer-owned JWKS. The
holder embeds a public key in sub_jwk, signs the ID Token with that key,
and uses the key's RFC 7638 SHA-256 thumbprint as sub. verify/2 ties all
three values together before returning the verified subject and public key.
This module implements the JWK Thumbprint Subject Syntax Type from
Self-Issued OpenID Provider v2 draft 13, section 11.1. It accepts sub_jwk
in the payload, as the current draft specifies, and in the protected JOSE
header for wallet interoperability. If both locations are present, their
JWK maps must be identical.
The current draft identifies a Self-Issued ID Token with iss == sub.
https://self-issued.me/v2, used by the earlier static-discovery model, is
also accepted for compatibility. DID subjects are deliberately out of
scope: they require method-specific DID resolution rather than an embedded
sub_jwk.
Verification is conn-free and fail-closed:
- the compact JWS must be canonical and carry no unsupported critical headers;
algmust be an Attesto-supported asymmetric algorithm allowed by RP policy and compatible with a public verification JWK;- the signature must verify strictly with the embedded holder key;
submust exactly equal the key's RFC 7638 thumbprint;issmust equal eithersuborhttps://self-issued.me/v2;audmust contain the RP Client ID andnoncemust exactly match the Authentication Request;expandiatare required non-negative NumericDates;nbfis optional but, when present, must also be a non-negative NumericDate. Expired and not-yet-valid tokens are rejected.
Claims other than the cryptographically bound sub remain self-attested.
Summary
Functions
Verify a Self-Issued ID Token and return its subject and holder public JWK.
Verify a Self-Issued ID Token against an RP Client ID and request nonce.
Types
@type verify_error() ::
:invalid_token
| :unsupported_critical_header
| :unexpected_typ
| :invalid_alg
| :missing_sub_jwk
| :invalid_sub_jwk
| :invalid_signature
| :invalid_subject
| :invalid_issuer
| :invalid_audience
| :invalid_nonce
| :invalid_claims
| :expired
| :not_yet_valid
@type verify_opts() :: [ audience: String.t(), nonce: String.t(), now: DateTime.t() | non_neg_integer(), accepted_algs: [Attesto.SigningAlg.alg()] ]
Functions
@spec verify(String.t(), verify_opts()) :: {:ok, verified()} | {:error, verify_error()}
Verify a Self-Issued ID Token and return its subject and holder public JWK.
Required options:
:audience- the RP Client ID sent in the Authentication Request. The token'saudmay be this string or an all-string array containing it.:nonce- the nonce sent in the Authentication Request. SIOPv2 requires it to be present and identical in the Self-Issued ID Token.
Optional options:
:now- clock reference as aDateTimeor Unix seconds.:accepted_algs- holder signature algorithms accepted by RP policy. Defaults toAttesto.SigningAlg.allowed/0;none, MAC algorithms, and algorithms unsupported by Attesto remain rejected even if listed.
The convenience verify/3 form accepts id_token, audience, and nonce
as positional arguments and applies the default clock and algorithm policy.
@spec verify(String.t(), String.t(), String.t()) :: {:ok, verified()} | {:error, verify_error()}
Verify a Self-Issued ID Token against an RP Client ID and request nonce.