AUTH4D-265 ID token and userinfo claims: email, email_verified and idp
The ID token (from POST /oauth/token, for both the authorization_code and the refresh_token
grant) and GET /oauth/userinfo now follow one rule for the address and both name the sign-in
method. The wire shapes are the AUTH4D-258 contracts (auth4d-258.md (repository file docs/api-spec/auth4d-258.md)). sub is
unchanged.
email and email_verified
Both appear only when the email scope was granted and the user has a provider email identity
with a verified address: one proven to auth4.dev by an email code, magic link or password sign-in,
by the add-email intent (auth4d-149.md (repository file docs/api-spec/auth4d-149.md)) or by the verified email step
(auth4d-262.md (repository file docs/api-spec/auth4d-262.md)).
emailis the stored address, lower-cased.email_verifiedis alwaystrue.- Otherwise both keys are left out. Neither is ever
null, andemail_verifiedis neverfalse. - An address a social provider sent (Discord, Google, an SSO connection) never becomes a claim, even when the provider marked it verified.
The ID token takes the address when the authorization code is issued. Since AUTH4D-332 a refresh
reads the user’s verified email identity again, so a refreshed ID token carries a changed address,
or none once it was removed or moved (auth4d-332.md (repository file docs/api-spec/auth4d-332.md)). Userinfo reads the user’s
identities on every call.
{
"sub": "usr_...",
"email": "player@example.com",
"email_verified": true,
"idp": "steam"
}
A Steam player with no verified address gets { "sub": "usr_...", "idp": "steam" }.
idp
idp names the method used for the sign-in that created the session, from the IdpSchema list in
auth4d-258.md (repository file docs/api-spec/auth4d-258.md):
| Sign-in | idp |
|---|---|
| Hosted login with a provider proof | what the proof recorded: email, password, magic_link, steam, etc. |
prompt=none reusing a hosted-login session |
session |
Hosted guest start (/t/{tenantId}/guest/authorize) |
guest |
- It is stored with the authorization code and then with the session, so a refreshed ID token, and userinfo called with a refreshed access token, still name the original method.
- The verified email step does not change it: a Steam sign-in that passed the step stays
steam. - Userinfo returns the
idpof the session behind the access token. It needs no scope. - A session created before this release has no stored method, so its tokens and userinfo omit
idpuntil the player signs in again. - Tokens from the device grant and from the add-email intent’s replacement session don’t carry
idpyet.
Access tokens
Access tokens do not carry idp. The access-token contract accepts the claim, but server SDKs
released before AUTH4D-258 check access tokens against a strict claim list and would refuse it.
Resource servers that need the sign-in method can call userinfo.
Flows
Flows token patches only reach auth4_roles and auth4_meta, so they never touch the top-level
claims above. idp joins FLOW_RESERVED_CLAIMS beside email and email_verified (already
reserved through RESERVED_CLAIM_NAMES), so a flow can’t name a claim idp either: a hook
decision or step that does is refused like any other reserved name.
Source: docs/api-spec/auth4d-265.md