Userinfo
Read the signed-in person's profile claims with an access token, and what the endpoint refuses.
On this page
The userinfo endpoint returns profile claims for the person an access token was issued for. Use it when you need profile data that is not in the ID token, or fresher than the ID token. It returns nothing about authorization: roles and permissions are never here.
Request#
GET or POST the userinfo_endpoint from discovery, which is /userinfo. Send the access token in the Authorization header.
| Token | Header |
|---|---|
| A DPoP-bound token (the usual case) | Authorization: DPoP <token> and DPoP: <proof>. The proof must carry ath, the hash of the token, and a current server nonce. |
| An unbound token | Authorization: Bearer <token> |
There are no other parameters. A token in the query string is refused with invalid_request, because addresses end up in logs.
What the token must be#
- Issued to a person. A token from
client_credentialsor a token exchange is refused asinvalid_token. - Carrying the
openidscope. Without it the answer is403 insufficient_scope. - Addressed to your client or to the issuer. A token you requested for a resource (its
audis the resource address) is not accepted here; ask for the profile with the ID token, or request a second token withoutresource. - Still live. If the session behind the token has ended, or the person or the client is no longer active, the token is refused. A token revoked at the revocation endpoint is refused too.
- Bound to the key you prove, when it is a DPoP token.
Response#
200 with Content-Type: application/json and Cache-Control: no-store. A DPoP request also gets a fresh DPoP-Nonce header.
| Member | Released when |
|---|---|
sub | Always. For a client registered pairwise it is that client's per-sector sub, not the person's real one. |
name, locale, zoneinfo, preferred_username, picture, updated_at | The token carries profile. A claim the person has not set is left out. |
email, email_verified | The token carries email, and the person has a verified primary email. Otherwise both are left out. |
picture is an address on the issuer. A client registered pairwise gets no picture, because that address contains the real sub. updated_at is seconds since the epoch. A claim is left out rather than sent as null, so a missing claim means either it was not released to you or the person has none.
tid, tslug, acr, amr, auth_time and sid are not returned here, although the discovery document lists them under claims_supported: they are claims of the ID token and the access token. Read them from those. See the claims reference.
Errors#
| Status | Body and header | When |
|---|---|---|
400 | {"error": "invalid_request"} with WWW-Authenticate: Bearer error="invalid_request" | The token is in the query string, or the Authorization header is malformed or too large. |
401 | {"error": "unauthorized"} with a WWW-Authenticate offering Bearer and DPoP | No credentials, or a scheme other than Bearer or DPoP. |
401 | invalid_token | The token is unreadable, expired, revoked, from an ended session, for a suspended client, not for a person, not addressed to this endpoint, or fails its key binding. |
401 | use_dpop_nonce with a DPoP-Nonce header | The proof lacks a current nonce. Retry once with the header value. |
403 | insufficient_scope with the required scope in WWW-Authenticate | The token does not carry openid. |
429 | Retry-After header | The request was refused for sending too many requests. Wait that long. |
The error codes follow RFC 6750 and RFC 9449. Identity does not say which check failed for an invalid_token.
Worked example#
curl -s https://identity.tdacorp.in/userinfo \ -H "Authorization: DPoP $ACCESS_TOKEN" \ -H "DPoP: $DPOP_PROOF"{ "sub": "0194f2b6-7c1e-7a30-9d4e-2f6f0f3b8c11", "name": "Asha Rao", "locale": "en", "zoneinfo": "Asia/Kolkata", "preferred_username": "asha", "updated_at": 1790000000, "email": "asha@example.com", "email_verified": true}The values are illustrative.
Security notes#
- Key accounts on
sub. It is stable and never reused.preferred_username,nameandemailcan change and, for a username, can later belong to someone else. - Do not cache for long. A profile can change at any time. Do not use userinfo to decide what a person may do.
- Browser applications. A browser application served from a registered client origin may call this endpoint cross-origin. Keep the token out of storage that other scripts can read.
- Bind to the right token. Never send an access token meant for your API to someone else's server. Send the token only to identity's endpoint from discovery.