OIDC is the standard behind 'Sign in with...' and enterprise single sign-on.
OpenID Connect (OIDC) is a thin identity layer on top of OAuth 2.0. Add scope=openid to an authorization code request and the token response also contains an ID token: a signed JWT, addressed to the client, stating who the user is and how they authenticated.
Important ID token claims:
iss(the provider),sub(stable, unique user id within that issuer),aud(yourclient_id).exp,iat, andauth_time(when the user actually authenticated).nonce: the random value your client sent in the authorize request; it must match, to stop replayed ID tokens.- Optional profile claims like
email,email_verified,name, depending on scopes (profile,email).
Identify users by the pair (`iss`, `sub`), never by email: emails change and can be reused, and some providers do not verify them.
The userinfo endpoint returns profile claims when called with the access token. Providers publish everything else (endpoints, supported algorithms, signing keys) in a discovery document at /.well-known/openid-configuration.
Keep the token roles straight: the ID token is for the client to establish a login session and is never sent to APIs; the access token is for APIs. After validating the ID token, most web apps create their own session cookie and discard the ID token (keeping it only as id_token_hint for logout).
Example
// Decoded ID token payload (after signature validation!)
const idToken = {
iss: "https://accounts.example.com",
sub: "248289761001", // stable user id at this issuer
aud: "web-app", // must equal our client_id
nonce: "n-0S6_WzA2Mj", // must equal the nonce we sent
iat: 1760000000,
exp: 1760003600,
auth_time: 1759999990,
email: "ann@example.com",
email_verified: true,
};
function userKey(t, expected) {
if (t.iss !== expected.iss || t.aud !== expected.clientId) throw new Error("wrong issuer/audience");
if (t.nonce !== expected.nonce) throw new Error("nonce mismatch");
return `${t.iss}|${t.sub}`; // identify users by (iss, sub)
}
console.log(userKey(idToken, { iss: "https://accounts.example.com", clientId: "web-app", nonce: "n-0S6_WzA2Mj" }));
// https://accounts.example.com|248289761001Remember
scope=openidadds a signed ID token for the client- Identify users by (iss, sub), not by email
- Check
aud= your client_id andnonce= what you sent - ID token for the client, access token for APIs
Watch out for
- Sending the ID token to your API as if it were an access token.