OIDC contract for the Wallet Portal
The rule
wallet.oid4pay.com/login uses OIDC against the AS:
response_type=codeonly (nevertokenorid_token; both deprecated)- PKCE S256 REQUIRED
nonceREQUIRED in auth request and validated in ID Token- ID Token claims:
iss=https://as.oid4pay.com,sub=<principal_id>,aud=<wallet_client_id>,exp,iat,auth_time,nonce,c_hash,acr,amr acrvalues:urn:oid4pay:pwd(password baseline),urn:oid4pay:webauthn:2fa(WebAuthn two-factor)amrvalues array:["pwd"],["pwd","webauthn"]- ID Token signed with Ed25519; the ID-Token and AT signing keys are separate
- Wallet Portal validates
issmatchesas.oid4pay.comper RFC 9207 §2.4 to defeat mix-up attacks stateREQUIRED on auth request per RFC 9700 §4.7
Discovery document
The AS publishes its OIDC metadata at the RFC 8414 path:
GET /.well-known/oauth-authorization-server HTTP/1.1
Host: as.oid4pay.com
200 OK
{
"issuer": "https://as.oid4pay.com",
"authorization_endpoint": "https://as.oid4pay.com/oauth/authorize",
"pushed_authorization_request_endpoint": "https://as.oid4pay.com/oauth/par",
"require_pushed_authorization_requests": true,
"token_endpoint": "https://as.oid4pay.com/oauth/token",
"introspection_endpoint": "https://as.oid4pay.com/oauth/introspect",
"revocation_endpoint": "https://as.oid4pay.com/oauth/revoke",
"registration_endpoint": "https://as.oid4pay.com/oauth/register",
"jwks_uri": "https://as.oid4pay.com/oauth/jwks.json",
"scopes_supported": ["openid", "email", "profile", "oid4ac:payment", "wallet:read", "wallet:write"],
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"code_challenge_methods_supported": ["S256"],
"token_endpoint_auth_methods_supported": ["private_key_jwt"],
"token_endpoint_auth_signing_alg_values_supported": ["EdDSA"],
"id_token_signing_alg_values_supported": ["EdDSA"],
"subject_types_supported": ["public"],
"dpop_signing_alg_values_supported": ["EdDSA", "ES256"],
"authorization_response_iss_parameter_supported": true,
"resource_indicators_supported": true,
"revocation_endpoint_auth_methods_supported": ["private_key_jwt", "none"]
}ID Token claim set
{
"iss": "https://as.oid4pay.com",
"sub": "principal_id_b64url",
"aud": "wallet_client_id",
"exp": 1747260600,
"iat": 1747260300,
"auth_time": 1747260280,
"nonce": "<the nonce the RP sent on the auth request>",
"c_hash": "<b64url(SHA-256(authorization_code)) first half>",
"acr": "urn:oid4pay:webauthn:2fa",
"amr": ["pwd", "webauthn"]
}RP verifier checklist
issmatches the AS issuer the RP is bound to.- Signature against AS JWKS,
alg=EdDSA. audequals the RP'sclient_id.expin future.iatwithin 60 s of clock.noncematches the RP-sent nonce.c_hashmatches the redeemed authorization code.- RFC 9207
issparameter on the authorization response matches the ID Tokeniss.
RFC 9207 mix-up defence
The authorization response carries an iss parameter on the redirect back to the RP. The
RP MUST match it against the issuer it initiated the flow with. Without this check, an attacker substituting
a hostile AS during the redirect leg could exchange a code with the legitimate RP's client_id at the wrong server.