In OpenID Connect, which claims do the profile and email scope values request, and which do they not?
answer
- scope values name bundles, not attributes
- the bundles are fixed by specification
- one of them is unexpectedly wide
- profile carries fourteen claims
- email brings email_verified with it
basics
~20 sThe 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.
solid answer
~40 sOpenID Connect defines four OPTIONAL identity scope values, each naming a fixed **claim set**. `profile` requests fourteen claims: `name`, `family_name`, `given_name`, `middle_name`, `nickname`, `preferred_username`, `profile`, `picture`, `website`, `gender`, `birthdate`, `zoneinfo`, `locale` and `updated_at`. `email` requests `email` and `email_verified`. `address` requests `address`, and `phone` requests `phone_number` and `phone_number_verified`. The mapping is fixed by the specification, so a client cannot ask for half of `profile` — asking for a display name means asking for a birth date and a gender too. Neither scope value covers the other's claims: `profile` does not carry `email`, and nothing in either carries a postal address. Anything narrower than a whole claim set has to be requested by claim name instead.
code
json · 15 lines{
"sub": "24400320",
"name": "Alex Moreau",
"family_name": "Moreau",
"given_name": "Alex",
"preferred_username": "amoreau",
"picture": "https://idp.example.org/u/24400320/avatar",
"gender": "female",
"birthdate": "1987-04-21",
"zoneinfo": "Europe/Paris",
"locale": "fr-FR",
"updated_at": 1748611200,
"email": "[email protected]",
"email_verified": true
}go deeper
Recall which scope value brings back which attributes: profile for names and profile-page details, email for the address and its verified flag, address and phone for their own claims. Know that email is not inside profile.
Explain that the mapping is fixed by the specification and cannot be narrowed, that all four are OPTIONAL scope values a provider need not support, and that a requested claim may still be absent from the response.
Demonstrate that you size the request against the task: justify each scope value by what the application must store, and show how a request written once quietly determines the personal data the system will hold for years.
Treat the scope list as a standing data-collection policy across every integration in the estate, decided against retention and deletion obligations rather than per-team convenience, and reviewed when a new claim set is added.
## A scope value is a pre-agreed bundle In OpenID Connect a scope value on the authorization request does two different jobs depending on which value it is. `openid` switches the identity layer on. `profile`, `email`, `address` and `phone` each select a **claim set** — a fixed, specification-defined group of attributes about the end user. The client does not name the attributes; it names the bundle, and the bundle's contents are the same at every conforming provider. All four are **OPTIONAL** scope values. A provider is a conforming OpenID Provider without supporting any of them, and advertises the ones it does accept in the `scopes_supported` member of its configuration document. ## The four claim sets, exactly | Scope value | Claims it requests | |---|---| | `profile` | `name`, `family_name`, `given_name`, `middle_name`, `nickname`, `preferred_username`, `profile`, `picture`, `website`, `gender`, `birthdate`, `zoneinfo`, `locale`, `updated_at` | | `email` | `email`, `email_verified` | | `address` | `address` | | `phone` | `phone_number`, `phone_number_verified` | Fourteen claims in `profile`, two in `email`, one in `address`, two in `phone`. Three details in that table are worth saying out loud: - **`profile` is a claim name as well as a scope value.** The `profile` claim is a URL for the end user's profile page; the `profile` scope value is the request for the whole bundle that contains it. Same word, two objects. - **`email_verified` and `phone_number_verified` are booleans about the provider's own verification**, and they travel with their value claim rather than being separately requestable by scope. - **`address` is a structured claim**, not a string, and it is the only member of its claim set. ## What no scope value selects The subject identifier is not scope-selected: an ID token identifies the end user whether or not any of these four values was asked for. Claims outside the standard set — anything a deployment invents for its own purposes — are not selected by these scope values either. And a scope value is a **request**, not a guarantee: a provider returns the claims it holds and is permitted to release, and a request for `profile` at a provider that stores no birth date simply comes back without `birthdate`. ## Why the width matters The mapping is all-or-nothing, and that is the trap. There is no scope value for "just the display name". A client that needs one name asks for `profile` and receives thirteen further claims it never wanted, including two — `birthdate` and `gender` — that most privacy regimes treat as sensitive personal data the moment they land in a database. Run the nature reserve's species-sighting recorder through it. Each sighting record needs a label saying which ranger filed it. The developer wants a human-readable name rather than an opaque identifier, adds `profile` to the request, and ships. From that day the recorder receives a birth date, a gender, a time zone, a locale, a profile-page URL and a picture URL for every ranger on the reserve, stores whatever its user table happens to have columns for, and writes the rest into a log. Nothing fails. There is no error, no warning and no ticket. A year later somebody asks which personal data the reserve holds, and the answer is a surprise to everyone. The defect is not a bug in the code. It is a request that asked for more than the task needed, and the request is where it has to be fixed. ## Asking narrower There are two honest ways out, in order of preference: 1. **Do not ask.** If a stable per-user key is enough for the label, `scope=openid` alone is the whole request and the recorder holds no personal attributes at all. 2. **Ask by claim name.** Where the provider supports it, an individual claim can be requested by name instead of by bundle, which is how a client asks for `name` without also receiving `birthdate`. What is *not* a way out is filtering after the fact. Discarding the unwanted claims in application code still means they crossed the network, sat in a response body, and very probably appeared in a log line written before the filter ran. ## The interview version of this Being able to recite fourteen claim names is worth little on its own. What an interviewer is checking is whether the candidate knows the mapping is fixed and coarse, and therefore treats the scope list as a data-collection decision made at integration time rather than as boilerplate copied from a quickstart.
- A client needs only a display name. What is the least it can ask for?Ideally `scope=openid` alone, using the subject identifier as the key and holding no attributes. Where a human-readable label is genuinely required, request the `name` claim by name rather than adding the `profile` scope value, which drags in thirteen further claims including `birthdate` and `gender`.
- The request asked for profile but the response has no birthdate. Is that an error?No. A scope value requests a claim set; it does not oblige the provider to produce values it does not hold or may not release. A claim simply absent from the response is the normal case, and a client must treat every scope-selected claim as optional.
- What does email_verified actually assert?That the provider took some steps to verify the address was controlled by the end user at some point, under its own policy — not that the address is correct now, and not that it is unique. Two accounts at the same provider can carry the same verified address unless that provider forbids it.
A scope value is a pre-printed order form, not a blank one. Ticking the profile box orders the whole fourteen-line form, including the lines about birth date and gender you never meant to collect.
saying these in an interview costs you the question
- Thinks profile can be narrowed to a few claims
- Believes profile includes email or a postal address
- Assumes every requested claim always comes back
- Treats email_verified as proof the address is current
- Filters unwanted claims after receiving them, and calls that minimisation