ID token & UserInfo
העתקת עמוד
The id_token claims — including amr (how the user authenticated) and auth_time — and the UserInfo endpoint (GET|POST /api/oauth/userinfo) that returns scope-gated identity claims.
עודכן
OpenID Connect gives you two sources of identity: the id_token returned by the token endpoint (a signed statement about who signed in and how), and the UserInfo endpoint (a live, server-verified lookup of the user’s claims). Both are gated by the scopes the user granted.
The id_token
Issued when the openid scope is granted. It is an RS256 JWT (typ: JWT) that verifies offline against the JWKS.
Claims
| Claim | Always | Meaning |
|---|---|---|
iss | ✓ | Issuer — https://entrybit.net. |
sub | ✓ | Stable EntryBit user identifier. |
aud | ✓ | Your client_id. |
iat | ✓ | Issued-at (Unix seconds). |
exp | ✓ | Expiry (Unix seconds). |
nonce | Echoed from your authorize request — verify it matches. | |
auth_time | When the user actually authenticated (Unix seconds). | |
amr | How the user authenticated (see below). | |
at_hash | Binds the id_token to the access token. | |
email, email_verified | With the email scope. | |
name, picture | With the profile scope. |
amr — how the user signed in
The amr (Authentication Methods References, RFC 8176) array records the factors used at login. EntryBit stamps these values:
| Value | Meaning |
|---|---|
pwd | Password. |
otp | One-time code (authenticator / email). |
sms | SMS one-time code. |
swk | Passkey (software-backed key). |
user | Passkey with user verification. |
fed | Federated login (Google). |
mfa | Two or more factors were used. |
For example, ["swk","user"] is a verified passkey, ["pwd","otp","mfa"] is password plus a code, and ["fed"] is Google. Combined with auth_time, this lets a sensitive screen require a recent or stronger login — request one with prompt=login or max_age on the authorize request.
Validating it yourself
If you decode the id_token on the client, fully validate the JWT — do not trust decoded claims blindly:
- Verify the signature against
/.well-known/jwks.json. - Check
iss==https://entrybit.net. - Check
aud== yourclient_id. - Check
expis in the future. - Check
nonceequals the value you sent (so makenoncerequired if you consume the id_token). Many libraries — includingexpo-auth-session— do not validate id_tokens for you.
With jose in Node.js, steps 1–4 are options and step 5 is yours:
// npm install jose
import { createRemoteJWKSet, jwtVerify } from 'jose';
const JWKS = createRemoteJWKSet(new URL('https://entrybit.net/.well-known/jwks.json'));
export async function verifyIdToken(idToken: string, expectedNonce: string) {
// Steps 1–4 — signature, iss, aud, exp — enforced by jose.
const { payload } = await jwtVerify(idToken, JWKS, {
issuer: 'https://entrybit.net',
audience: CLIENT_ID,
algorithms: ['RS256'],
});
// Step 5 — the nonce binds this id_token to YOUR authorize request.
if (payload.nonce !== expectedNonce) {
throw new Error('id_token nonce mismatch — possible replay');
}
return payload; // { sub, amr?, auth_time?, email?, name?, … }
}If you only need the user’s profile, prefer UserInfo below — it is already server-verified.
UserInfo endpoint
Returns the signed-in user’s claims, gated by the granted scopes. Available over GET and POST (OIDC Core §5.3.1 — the two are identical).
GET /api/oauth/userinfo
POST /api/oauth/userinfo
Authorization: Bearer <access_token>Requires the openid scope. The email and profile scopes gate their respective claims.
curl https://entrybit.net/api/oauth/userinfo \
-H "Authorization: Bearer $ACCESS_TOKEN"Response
{
"sub": "usr_9f1c2ab34cd56ef7",
"email": "dana@example.com",
"email_verified": true,
"name": "Dana Cohen",
"picture": "https://entrybit.net/…"
}| Field | Present when |
|---|---|
sub | Always (with openid). |
email, email_verified | The email scope was granted. |
name, picture | The profile scope was granted. |
Errors
401/403 responses carry a WWW-Authenticate: Bearer challenge:
| Status | error | Meaning |
|---|---|---|
401 | invalid_token | Missing, expired, or invalid access token — refresh or re-login. |
403 | insufficient_scope | The token lacks openid. |
See Errors for the full Bearer-challenge contract.