skip to content

Assertion Format

What a provider asserts about a user: the ID token and its claims, the claim sets scopes unlock, UserInfo, and how the subject is named. The half you can reason about without a browser.

part ofFederated identityoverview, primer and where to startread it →
on this pageshow

questions

16

In OpenID Connect, what does an ID token tell a relying party that an access token never does?

level: juniorimportance: must knowfreq 74%

answer

  1. two artefacts, two different readers
  2. who signed in, not what may be done
  3. the client is the addressee
  4. iss, sub, aud, exp, iat are REQUIRED
  5. consumed at login, never sent to an API

basics

~20 s

An OpenID Connect ID token is a signed statement, addressed to the client that asked, that a named user just authenticated at a named issuer. An access token authorises an API call and says nothing about who signed in.

solid answer

~50 s

The ID token is the one artefact the identity layer adds on top of delegated authorization: a signed JSON Web Token in which a provider states that a particular end user authenticated, for a particular client, at a particular moment. Its `iss`, `sub`, `aud`, `exp` and `iat` claims are REQUIRED here, and the relying party is the addressee — it validates the token, reads who signed in, establishes its own application session, and is done with it. An access token is the opposite artefact: a credential addressed to a resource server, saying what the bearer may do and carrying no promise that the user is present now. Forwarding an ID token to an API as `Authorization: Bearer` is the classic error, because the API is not named in `aud` and the ID token encodes no delegated scope at all.

code

json · 6 lines
json
{
  "access_token": "SlAV32hkKG",
  "token_type": "Bearer",
  "expires_in": 3600,
  "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzcyI6..."
}

go deeper

for a junior

Recall that there are two different artefacts and two different readers: the ID token goes to the application that started the login, the access token goes to the API.

for a middle

Explain the five required claims and what each one lets the client decide, and be able to say why an API rejecting an ID token is behaving correctly rather than being awkward.

for a senior

Show that you have seen the forwarding mistake in production, can describe what the API was actually checking when it accepted one, and can state what breaks in the audit trail afterwards.

for a principal

Frame it as an addressing discipline across an estate: every credential has one intended reader, and the cost of blurring that is authorisation decisions made on statements nobody addressed to the decider.

## The one artefact the identity layer adds OpenID Connect is a thin identity layer laid over a delegated-authorization framework. The redirect out to a provider and the back-channel exchange that follows belong to the framework underneath; what the identity layer adds is a single extra artefact, the **ID token**. It is a signed JSON Web Token — the container is defined by **RFC 7519** — in which an OpenID Provider states that a particular end user authenticated, at a particular issuer, for a particular client, at a particular moment. It is returned when the authentication request asked for the `openid` scope. The load-bearing word is *addressed*. Every artefact in this family is addressed to someone, and nearly every serious mistake here is an artefact being read by a party it was never addressed to. ## Who reads which artefact | Artefact | Addressed to | Answers | Validated by | |---|---|---|---| | ID token | the client (relying party) | who just signed in, at which issuer | the client, against the issuer's published key | | Access token | the resource server | what the bearer may do | the resource server | | Refresh token | the authorization server | may this client obtain a new access token | the authorization server that issued it | An access token is a **bearer credential**: whoever holds it may exercise the grant it stands for, and it carries no promise that a user is at a browser right now — only that a grant existed when it was issued. An ID token is an **assertion about an authentication event**, consumed once, at login, by the client that asked for it. ## What the ID token carries Five claims are REQUIRED in an ID token, and "required" here is a stronger statement than the container format makes about the same names: - `iss` — the issuer identifier, which must exactly match the issuer the relying party has configured for this provider; - `sub` — the provider-local identifier for the user: locally unique, never reassigned within that issuer, case-sensitive, at most 255 ASCII characters; - `aud` — the audience, which MUST contain the relying party's own `client_id`; - `exp` — the instant after which the token must not be accepted; - `iat` — when the provider issued it. Optional members sit on top of those: `nonce`, which the provider MUST include when the request carried one; `azp`; `at_hash`; and assurance claims defined elsewhere in the specification. ## What the relying party does with it 1. Validate it — the issuer match, an audience containing its own `client_id`, the signature against the issuer's published key, and the expiry. 2. Read `sub` together with `iss` as the account key, plus whatever profile claims the requested scopes unlocked. 3. Establish its own application session. 4. Stop using the ID token as a credential. Step 4 is the one candidates miss. The ID token is consumed at the door. If the application later needs to call an API on the user's behalf it presents the **access token**, in an `Authorization: Bearer` header. The one place an ID token legitimately travels again is back to the provider itself, as a request parameter defined in another part of this specification — never to an API. ## The classic failure: forwarding the ID token to an API A team wires up sign-in, finds itself holding a signed token that contains the user's identity, and sends that token to its own API as the credential. It often appears to work, because a verification routine at the API checks a signature and an expiry and is satisfied. It is wrong in two separate ways. First, the audience. The API is not in `aud`; the client is. A resource server that accepts a token naming somebody else as its audience has discarded the only check that says the token was meant for it. Second, the semantics. The ID token records that someone *authenticated*. It says nothing about which permissions were delegated, and it has no scope of delegation at all. The access token is the artefact that encodes the grant. An API authorising on an ID token is authorising on "this person signed in somewhere", which is not a permission. ## What a good answer sounds like Name which party each artefact is addressed to, say that the relying party validates the ID token and then runs its own session, and give the audience check as the reason an API must refuse one. Candidates who have only copied an integration can list the claims; candidates who understand it can say who each claim is a statement *to*.

  • Which ID token claim ties it to one particular access token, and what does that let the client detect?
    `at_hash`. Its value is the base64url encoding of the left-most half of the hash of the access token's ASCII octets, using the hash algorithm that matches the ID token's signature algorithm. It is REQUIRED when an ID token and an access token are issued together from the authorization endpoint, and it lets the client notice that the access token beside the ID token has been swapped for another one.
  • A resource server is configured to accept ID tokens as bearer credentials. What is the concrete defect?
    It is validating a statement that was never addressed to it: `aud` names the client, not the API. It has also lost the grant boundary, because an ID token carries no delegated scope — so "this person logged in" becomes the whole authorization decision. The fix is to accept only access tokens whose audience is the API itself.
  • Does a valid signature on an ID token mean the relying party may trust its claims?
    No. A signature only says which key signed the bytes. The relying party must also confirm the issuer is the one it configured, that `aud` contains its own `client_id`, and that the token has not expired. Signature verification is a step in the routine, not the end of it.

A signed letter of introduction tells the person who opens it who you are; the numbered pass clipped to it opens certain doors and never says your name. Handing the letter to the door staff proves nothing to them, because it was not written to them.

saying these in an interview costs you the question

  • An ID token is just an access token that also carries the user's name.
  • Send the ID token to the API; it is signed, so it is safe.
  • A valid signature means the ID token was issued for you.
  • An access token tells the API which user is signed in right now.
  • The ID token replaces the application's own session.
open as a page

In OpenID Connect, which scope value must an authorization request include, and what does including it change?

level: juniorimportance: must knowfreq 74%

basics

~20 s

An authorization request becomes an OpenID Connect authentication request only when its scope parameter includes the value openid. That value makes the provider issue an ID token; without it the exchange is plain OAuth 2.0 authorization.

open as a page

At the OpenID Connect UserInfo endpoint, which credential does a relying party present, and what comes back?

level: juniorimportance: must knowfreq 64%

basics

~20 s

The UserInfo endpoint is an OAuth 2.0 protected resource. The relying party presents the access token from the same sign-in as a bearer credential over TLS, and receives a JSON object of claims about that end user.

open as a page

Why must an OpenID Connect relying party check that an ID token's aud claim contains its own client_id?

level: middleimportance: must knowfreq 66%

basics

~20 s

The aud claim is what says an ID token was issued for this client. A valid signature proves only which provider minted it, so skipping the audience check accepts a token minted for a different client registered at the same issuer.

open as a page

In OpenID Connect, which claims do the profile and email scope values request, and which do they not?

level: middleimportance: must knowfreq 62%

basics

~20 s

The profile scope value requests fourteen claims — name, family_name, given_name, middle_name, nickname, preferred_username, profile, picture, website, gender, birthdate, zoneinfo, locale and updated_at — while email requests email and email_verified. A scope value is all-or-nothing.

open as a page

In OpenID Connect, why must a UserInfo response's `sub` be compared with the ID token's `sub` before use?

level: middleimportance: must knowfreq 55%

basics

~20 s

Because the access token used to call UserInfo may have been issued for a different end user. The subject values must match exactly, and if they do not, none of the response values may be used at all.

open as a page

In OpenID Connect, what does the nonce claim in an ID token bind that token to?

level: middleimportance: should knowfreq 54%

basics

~20 s

The nonce binds an ID token to the one authentication request that carried the same nonce value. The client generates it, sends it, and must reject any ID token whose nonce claim is not exactly the value it sent.

open as a page

In OpenID Connect, an authorization request asks for offline_access and the provider ignores it — which conditions were unmet?

level: middleimportance: should knowfreq 46%

basics

~20 s

A provider must ignore offline_access unless the client uses a response_type that returns an authorization code, and unless prompt=consent is present or other permitting conditions already apply. It asks for a refresh token usable without the end user.

open as a page

In OpenID Connect, what does a subject_type of pairwise change about the sub claim compared with public?

level: middleimportance: should knowfreq 48%

basics

~20 s

A pairwise subject_type makes the provider issue a different sub value to each client for the same end user, so no two clients can match their user records. Public gives every client the identical sub.

open as a page

What does an OpenID Connect ID token's exp claim bound, and why is it not a relying party's session lifetime?

level: seniorimportance: should knowfreq 44%

basics

~20 s

The exp claim bounds acceptance of the login assertion itself: after that instant the ID token must not be accepted. The specification states it is unrelated to the lifetime of the authenticated session between relying party and provider, which the protocol never sets.

open as a page

In OpenID Connect, what does the claims request parameter let a client ask for that a scope value cannot?

level: seniorimportance: should knowfreq 30%

basics

~20 s

The claims request parameter asks for individual claims by name, in a JSON value whose top-level members are userinfo and id_token, and can mark one essential. Scope values can only select whole predefined claim sets.

open as a page

In OpenID Connect, when is a UserInfo round trip worth making if the ID token already carries the attributes?

level: seniorimportance: should knowfreq 46%

basics

~20 s

When the attribute can change between sign-ins. An ID token is a snapshot frozen when it was minted; a UserInfo call is answered now. The round trip buys freshness, and buys nothing for values that cannot move.

open as a page

In OpenID Connect, why must a provider settle its public-or-pairwise subject_type policy before the first relying party integrates?

level: principalimportance: should knowfreq 34%

basics

~20 s

Every sub a relying party has stored is a product of that policy. Change subject_type, or move a client between sectors, and the provider starts issuing unrelated values, orphaning every account record keyed on the old ones.

open as a page

When does an OpenID Connect UserInfo response arrive as `application/jwt` instead of `application/json`?

level: middleimportance: nice to knowfreq 28%

basics

~20 s

When the client registered for a signed or encrypted response. Plain claims come back as a JSON object with media type application/json; signed, encrypted, or signed-then-encrypted claims come back as a token with media type application/jwt.

open as a page

In an OpenID Connect claim set, what do _claim_names and _claim_sources indicate about where a claim came from?

level: seniorimportance: nice to knowfreq 18%

basics

~20 s

_claim_names maps a claim to a key in _claim_sources, which says where it came from: an aggregated claim arrives as a signed JWT inside the response, a distributed claim only as an endpoint to fetch it from.

open as a page

In OpenID Connect, how can three clients run by one organisation receive the same pairwise sub for one user?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

Register all three clients with the same sector_identifier_uri. A pairwise value is derived per sector rather than per client, and the Sector Identifier is that URI's host component, so the three resolve to one sector and one shared sub.

open as a page