Summary
Accept the OIDC Identity Assurance (IDA) verified_claims member in the userinfo
section of the authorize claims parameter, store it in the authorization request
store, and ignore it everywhere else.
ClaimsRequest.UserInfo (currently map[string]*IndividualClaimRequest) cannot hold a
verified_claims value, whose request form is the nested IDA structure
(verification + claims), not the {essential, value, values} shape. Widening
UserInfo to map[string]any lets it carry both normal claims and verified_claims.
This is accept-and-store only: Thunder never resolves, verifies, or returns
verified_claims.
Goals
- Change
ClaimsRequest.UserInfo to map[string]any.
- Validate
userinfo.verified_claims against the IDA request structure; keep existing
OIDC validation for normal claims.
- Persist
verified_claims in auth_req_store (DB JSONB + cache) and reconstruct it
faithfully on retrieval.
- Keep all other consumers (essential/optional classification, claim filtering,
sub-claim constraint, UserInfo/token building) operating only on normal claims.
Non-goals
- No
verified_claims in the id_token section; ClaimsRequest.IDToken is unchanged.
- No resolution, verification, or return of
verified_claims in any output.
- No new data model, schema change, or client config for verified data
(verified_claims rides inside the existing REQUEST_DATA JSONB).
Acceptance criteria
ClaimsRequest.UserInfo is map[string]any; IDToken unchanged; existing tests
pass after consumers are adapted.
- A
claims parameter with userinfo.verified_claims is accepted and the value is
retained in the parsed ClaimsRequest.
- Full IDA validation: malformed
verified_claims (missing verification /
trust_framework / claims) is rejected with invalid_request; both object and
array-of-objects forms are accepted when valid. Normal-claim validation is unchanged.
- Round-trip: after persist + reload (DB and cache), the reconstructed
verified_claims
equals the submitted one.
verified_claims never appears in required-attribute sets, BuildClaims output, the
UserInfo response, ID token, access token, or sub-claim constraint checks. Responses
for normal claims are identical with or without verified_claims present.
- Unit tests cover parsing, IDA validation (valid/invalid/array), the store round-trip,
and the "ignored everywhere else" guarantees.
Known edge cases / risks / dependencies
- Normalization: with
UserInfo as map[string]any, every non-verified_claims
entry must be re-decoded into *IndividualClaimRequest wherever the old code iterated
typed values. A null value ("email": null) still means "requested, no constraint".
Centralize the verified_claims exclusion in one helper to keep the no-leakage
guarantee robust.
- Shape variants: accept single-object and array-of-objects
verified_claims;
aggregated/distributed forms are out of scope (stored opaquely).
- Round-trip fidelity:
parseClaimsRequestFromJSON must avoid lossy coercion (e.g.
numeric handling) so the reloaded value matches the original.
- Wider consumer surface: the type change touches every reader of
UserInfo; a
missed site either fails to compile or mis-handles normal claims — covered by tests.
- Dependency: OIDC IDA spec for the
verified_claims request structure; existing
auth_req_store and claims parse/validate utilities
(oauthutils.go, model/parameter.go).
Summary
Accept the OIDC Identity Assurance (IDA)
verified_claimsmember in theuserinfosection of the authorize
claimsparameter, store it in the authorization requeststore, and ignore it everywhere else.
ClaimsRequest.UserInfo(currentlymap[string]*IndividualClaimRequest) cannot hold averified_claimsvalue, whose request form is the nested IDA structure(
verification+claims), not the{essential, value, values}shape. WideningUserInfotomap[string]anylets it carry both normal claims andverified_claims.This is accept-and-store only: Thunder never resolves, verifies, or returns
verified_claims.Goals
ClaimsRequest.UserInfotomap[string]any.userinfo.verified_claimsagainst the IDA request structure; keep existingOIDC validation for normal claims.
verified_claimsinauth_req_store(DB JSONB + cache) and reconstruct itfaithfully on retrieval.
sub-claim constraint, UserInfo/token building) operating only on normal claims.
Non-goals
verified_claimsin theid_tokensection;ClaimsRequest.IDTokenis unchanged.verified_claimsin any output.(
verified_claimsrides inside the existingREQUEST_DATAJSONB).Acceptance criteria
ClaimsRequest.UserInfoismap[string]any;IDTokenunchanged; existing testspass after consumers are adapted.
claimsparameter withuserinfo.verified_claimsis accepted and the value isretained in the parsed
ClaimsRequest.verified_claims(missingverification/trust_framework/claims) is rejected withinvalid_request; both object andarray-of-objects forms are accepted when valid. Normal-claim validation is unchanged.
verified_claimsequals the submitted one.
verified_claimsnever appears in required-attribute sets,BuildClaimsoutput, theUserInfo response, ID token, access token, or sub-claim constraint checks. Responses
for normal claims are identical with or without
verified_claimspresent.and the "ignored everywhere else" guarantees.
Known edge cases / risks / dependencies
UserInfoasmap[string]any, every non-verified_claimsentry must be re-decoded into
*IndividualClaimRequestwherever the old code iteratedtyped values. A
nullvalue ("email": null) still means "requested, no constraint".Centralize the
verified_claimsexclusion in one helper to keep the no-leakageguarantee robust.
verified_claims;aggregated/distributed forms are out of scope (stored opaquely).
parseClaimsRequestFromJSONmust avoid lossy coercion (e.g.numeric handling) so the reloaded value matches the original.
UserInfo; amissed site either fails to compile or mis-handles normal claims — covered by tests.
verified_claimsrequest structure; existingauth_req_storeand claims parse/validate utilities(
oauthutils.go,model/parameter.go).