After this lesson, you will be able to: Implement API keys, Bearer tokens, JWT, and OAuth 2.0 flows correctly.
Authentication is where APIs get insecure. Use the standard patterns; don't invent your own.
A long random string. Sent in `Authorization: Bearer <key>` or a custom header (`X-API-Key: ...`). Use for: server-to-server, public read APIs, third-party integrations. Rotate them. Store them hashed (like passwords) so a DB breach doesn't expose them. NEVER ship API keys to the browser, they're meant for backend-to-backend.
Signed (or encrypted) tokens. Stateless auth.
// Structure: header.payload.signature, all base64-encoded// Example payload (decoded):{"sub": "user_42", // subject (user id)"role": "admin","iat": 1716777600, // issued at (unix time)"exp": 1716781200, // expires at (1 hr later)"iss": "myapp.com" // issuer}// Server signs the payload with a secret. Client cannot tamper without invalidating the signature.// On each request:Authorization: Bearer eyJhbGciOiJIUzI1NiIs...// Server verifies signature + expiry; trusts the payload.// Pros: stateless (no DB lookup per request).// Cons: can't revoke before expiry without a denylist (which defeats statelessness).
Modern, no-dependency lib.
// npm i joseimport * as jose from 'jose';const secret = new TextEncoder().encode(process.env.JWT_SECRET!);// Signconst token = await new jose.SignJWT({ sub: 'user_42', role: 'admin' }).setProtectedHeader({ alg: 'HS256' }).setIssuedAt().setExpirationTime('1h').setIssuer('myapp.com').sign(secret);// Verifytry {const { payload } = await jose.jwtVerify(token, secret, {issuer: 'myapp.com',});// payload.sub, payload.role available} catch (e) {// expired or tampered}
Authorization Code Flow with PKCE: the modern default for web + mobile + SPA. User clicks 'Sign in with Google,' redirected to Google, authorizes, redirected back with an authorization code, server exchanges code for access + refresh tokens. Client Credentials Flow: server-to-server (no user). Service A sends client_id + secret, gets token, calls service B. Refresh Token Flow: short-lived access tokens (~1 hour) + long-lived refresh tokens (~30 days). Client uses refresh token to silently get a new access token.
API keys in client-side JS / mobile app binaries (extractable in seconds). JWTs in localStorage (XSS = total takeover). Skipping `exp` claim → tokens valid forever. Verifying JWTs with the WRONG algorithm (algorithm confusion attack, always explicitly set + check alg). Storing refresh tokens unhashed in DB (DB breach = persistent account access).
Sign in and purchase access to unlock this lesson.