Combining claims from multiple sources
All domains, identifiers, and tokens in these examples are fictional.
The earlier OpenID Connect lessons cover everything an ordinary sign-in needs, from the request and the ID token to the account, the session, and logout. Advanced OIDC turns to extensions that solve narrower problems. Plenty of relying parties never use them, but each one answers a question the core design leaves open, and each builds on checks you already know.
The first question comes from the printer's checkout. Students get 20 percent off photo books, and until now a student had to upload a picture of a student card, which someone at the printing company checked by eye. It is slow, and a picture of a card is easy to edit. You study at Northfield University, and you would like the discount without the upload.
A statement the provider cannot make
The printer already trusts the photo service to say who you are. It does not trust the photo service to say whether you are a student, and it should not. The photo service has no authority over Northfield's enrollment records. If it simply added a claim of its own saying that you are a student, the printer would be relying on the photo service for a fact the photo service can only repeat.
The party that can make the statement is the university. In OpenID Connect terms, Northfield is acting as a claims provider: a server that makes statements about a person. An OpenID Provider is one kind of claims provider, for the claims it issues itself. Here the photo service and Northfield are separate claims providers with different authority, and the printer wants each fact from the one that knows it.
In this example, the photo service already holds what the printer needs. When you chose its student storage plan in September, the photo service sent you to Northfield's sign-in at https://id.northfield.example, and Northfield gave the photo service a signed statement that you are enrolled. The photo service kept that statement, and it can pass it on, unchanged, to an application you approve.
OpenID Connect defines three ways a claim can appear in an ID token or a UserInfo response. Normal claims are statements the OpenID Provider makes itself, and every claim in the earlier lessons was one. Aggregated claims are statements from another claims provider that the OpenID Provider carries inside its own response, as the photo service is about to do. Distributed claims are references that the relying party follows to fetch a statement from the claims provider itself, the subject of the Distributed claims lessons. Every provider must support normal claims. The other two are optional, and a provider that supports them lists aggregated or distributed in the claim_types_supported field of its metadata. A provider that leaves the field out supports normal claims only.
Reading the response
The printer reads your profile from the UserInfo endpoint, as before. With the student statement included, the response looks like this, with the remaining profile claims left out and the embedded JWT shortened for display:
HTTP/1.1 200 OK
Content-Type: application/json
{
"sub": "user-2048",
"name": "Robin Park",
"email": "[email protected]",
"email_verified": true,
"_claim_names": {
"https://id.northfield.example/enrolled": "src1"
},
"_claim_sources": {
"src1": {
"JWT": "eyJhbGciOiJFUzI1NiIsImtpZCI6Im5vcnRoZmllbGQtMjAyNi0wOCIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2lkLm5vcnRoZmllbGQuZXhhbXBsZSIs..."
}
}
}
The student claim does not appear among the normal claims. Two special members describe where to find it instead. _claim_names maps each claim name to a source, here labeled src1. _claim_sources holds the source under that label. For an aggregated claim, the source is an object with a JWT member, and that JWT must contain every claim that _claim_names points to it. Several claims can share one source, and one response can hold sources from several claims providers. The label means nothing outside this response. It says nothing about who signed the JWT. Only the JWT can tell the printer that.
The claim's name is a URL in Northfield's domain. Custom claims need names that cannot collide with anyone else's, as Standard and custom claims explained, and here that matters even more: claim names from the photo service and from every claims provider share the one list in _claim_names.
Decoded, the embedded JWT reads:
Header:
{
"alg": "ES256",
"kid": "northfield-2026-08",
"typ": "JWT"
}
Claims:
{
"iss": "https://id.northfield.example",
"iat": 1789380000,
"exp": 1801353600,
"https://id.northfield.example/enrolled": true
}
This is Northfield's statement, signed with Northfield's key northfield-2026-08. iss names Northfield, and the specification recommends that a claims provider always include it so that a relying party can find the keys to check the signature. iat records when Northfield made the statement, 10:00 UTC on 14 September 2026, and exp when it stops vouching for it, 31 January 2027. The statement was not made for this sign-in. It is already a few weeks old, and it will travel unchanged to every application you approve until it expires.
Notice what the JWT leaves out. There is no sub, so nothing in it names you, and no aud, so nothing names the printer. The specification discourages a sub in these JWTs unless it is your identifier at the claims provider, and it says nothing about an audience. The photo service's response is what connects the statement to user-2048, and the next lesson looks at what that means for the printer's trust.
A relying party that does not support aggregated claims sees two members it does not recognize and, following the usual rule for claims it does not understand, ignores them. It simply finds no student claim.
Asking for the claim
The printer does not need your enrollment status to print photos, so it asks for it only when it matters. When you choose the student discount at checkout, the printer sends you through the photo service again with a request that adds the claims parameter from Scopes and the claims parameter. Before URL encoding, its value is:
{
"userinfo": {
"https://id.northfield.example/enrolled": null
}
}
null asks for the claim in the default way, without marking it essential. The printer asks for it under userinfo because, with the code flow, it reads your profile from the UserInfo endpoint anyway. A provider can equally carry an aggregated claim in an ID token, with _claim_names and _claim_sources among the token's claims.
The photo service decides the rest. The specification leaves it to the OpenID Provider to decide when to use aggregated or distributed claims, and relying parties and providers often agree on it in advance. Here the photo service asks whether you want to share your Northfield enrollment with the printer. If you agree, it adds the stored JWT to the response. If you decline, or the statement has expired, the claim is simply missing, which is not an error. The printer offers the card upload instead.
The printer has preparation of its own to do. Accepting Northfield's statements is a trust decision separate from accepting the photo service's sign-ins, and the printer records it in its own configuration: Northfield's issuer, where to find its keys, the algorithm it signs with, and which claim names it may vouch for. Reading and validating aggregated claims puts that configuration to work.