advanced
JWT, OAuth, OpenID Connect, and SSO
Separate token formats from auth protocols, validate issuer/audience/expiry/signature, and integrate OAuth/OIDC/SSO without trusting client claims blindly.
JWT is a signed (or encrypted) token format — not an auth protocol by itself. OAuth 2.0 delegates authorization; OpenID Connect adds identity layers (ID token, UserInfo) on top. SSO uses a central IdP so users authenticate once across apps.
import { createRemoteJWKSet, jwtVerify } from 'jose';
const JWKS = createRemoteJWKSet(new URL('https://idp.example.com/.well-known/jwks.json'));
async function authenticateBearer(req) {
const token = req.headers.authorization?.replace(/^Bearer /, '');
const { payload } = await jwtVerify(token, JWKS, {
issuer: 'https://idp.example.com',
audience: 'api.example.com',
});
return payload;
}
Always validate `iss`, `aud`, `exp`, and signature — never trust client-decoded claims. Prefer short-lived access tokens plus refresh tokens stored securely. For opaque tokens, use introspection at the authorization server.
On interviews: OAuth flows (authorization code with PKCE for SPAs); difference between access and ID tokens; why JWT logout is hard without blocklists or short TTL.
Common pitfalls: accepting `alg: none`; storing refresh tokens in localStorage; confusing OAuth scopes with application permissions.
The trade-off is balancing simplicity, performance, safety, and operability — name which axis you optimized and what cost you accepted.
Checklist:
- Verify signature, issuer, audience, expiry.
- Use authorization code + PKCE for public clients.
- Short-lived access tokens; secure refresh handling.
- Map external identity to internal authorization separately.