User info and ID tokens
Learn who signed in, from the user info endpoint or the ID token.
User info
curl https://sso.castyr.cloud/oauth/userinfo \
-H "Authorization: Bearer cat_…"{
"sub": "3f2b8c1e-5a7d-4e19-9c0a-2d6f1b8e4a70",
"name": "Sam Rivera",
"preferred_username": "samstreams",
"picture": "https://…/avatar.png",
"email": "someone@example.com",
"email_verified": true
}You get only the claims your scopes allow:
| Claim | Scope needed |
|---|---|
sub | Always. The user's permanent id: use it as your key, not the username. |
name | profile or identify |
preferred_username | profile, identify or username. Users can change it. |
picture | profile, identify or avatar, when they have one |
email, email_verified | email, when they have one |
The token must be in the Authorization header; query-string tokens are refused. A token without any of
openid profile username avatar identify email gets 403 insufficient_scope. An expired or revoked one gets
401 with WWW-Authenticate: Bearer error="invalid_token".
ID token
When you ask for openid, the token response includes an id_token: a JWT signed with RS256. Verify it
before trusting it:
Fetch the public keys from https://sso.castyr.cloud/.well-known/jwks.json and pick the one whose kid
matches the token header. Cache the keys, and refetch on an unknown kid: keys rotate.
Check the signature with algorithm RS256 only.
Check iss is https://sso.castyr.cloud, aud is your client_id, and exp is in the future.
If you sent a nonce, check it matches.
| Claim | Meaning |
|---|---|
sub | The user's permanent id (same as user info) |
iss, aud, iat, exp | Issuer, your client_id, issued at, expiry |
auth_time | When the user last signed in to Castyr |
nonce | Your nonce, if you sent one |
at_hash | Binds the ID token to the access token issued with it |
The ID token carries no profile or email claims. Get those from user info.