Advanced
Quick reference for authentication — hashing recipes, cookie flags, JWT anatomy, OAuth/PKCE flow, RBAC, TOTP, and attack mitigations.
JWTOAuthHashingSessions
AuthN vs AuthZ
| Term | Question | Fail status |
| Authentication | Who are you? | 401 |
| Authorization | What can you do? | 403 |
Password Hashing
Argon2 (recommended)
import argon2 from 'argon2';
const hash = await argon2.hash(pw, { type: argon2.argon2id });
const ok = await argon2.verify(hash, pw); // constant-time
bcrypt
import bcrypt from 'bcrypt';
const hash = await bcrypt.hash(pw, 12); // cost factor 12+
const ok = await bcrypt.compare(pw, hash); // max 72 bytes
Rules
| Do | Don't |
| Argon2id / bcrypt / scrypt | MD5, SHA-1, SHA-256 |
| Per-user random salt (auto) | Plaintext or encryption |
| Constant-time verify | Leak which field was wrong |
Cookies & Sessions
Secure Cookie
Set-Cookie: __Host-sid=abc;
HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=28800
Cookie Flags
| Flag | Protects against |
| HttpOnly | XSS reading the cookie |
| Secure | Leak over plain HTTP |
| SameSite=Lax/Strict | CSRF |
| __Host- | Cookie scope confusion |
// Prevent fixation: new ID on login
req.session.regenerate(() => { req.session.userId = id; });
JWT
Anatomy
header.payload.signature (3 base64url parts)
header { "alg": "HS256", "typ": "JWT" }
payload { "sub", "role", "iat", "exp" }
signature HMAC(base64url(header)+"."+base64url(payload), secret)
// base64 = encoding, NOT encryption -> no secrets in payload
Sign & Verify
import jwt from 'jsonwebtoken';
const t = jwt.sign({ sub: id, role }, SECRET, { expiresIn: '15m' });
const c = jwt.verify(t, SECRET, { algorithms: ['HS256'] }); // pin alg!
// Authorization: Bearer <token>
Access vs Refresh
| Access | Refresh |
| Lifetime | 5–15 min | Days–weeks |
| Storage | Memory / header | HttpOnly cookie |
| Revoke | Wait for expiry | Server-side + rotate |
Sessions vs JWT
| Aspect | Session | JWT |
| State | Server-side | In token |
| Revoke | Instant | Hard |
| Scale | Shared store | Stateless |
| Best for | Web apps | APIs / mobile |
OAuth 2.0 / OIDC
Auth Code + PKCE
verifier = random(32)
challenge = base64url(sha256(verifier))
1. GET /authorize?response_type=code&client_id=APP
&redirect_uri=...&scope=openid%20profile&state=xyz
&code_challenge=CHALLENGE&code_challenge_method=S256
2. -> redirect back ?code=...&state=xyz (verify state!)
3. POST /token grant_type=authorization_code
&code=...&code_verifier=VERIFIER&redirect_uri=...
4. { access_token, refresh_token, id_token, expires_in }
Grants
| Grant | Use |
| Auth Code + PKCE | All user-facing apps |
| Client Credentials | Machine-to-machine |
| Refresh Token | Renew access token |
| Implicit / Password | Deprecated — avoid |
OAuth = authorization. OIDC adds id_token (JWT) for authentication.
RBAC & MFA
RBAC Middleware
const can = (perm) => (req, res, next) => {
if (!req.user) return res.status(401).end();
if (!ROLES[req.user.role]?.includes(perm))
return res.status(403).end();
next();
};
app.delete('/posts/:id', can('post:delete'), handler);
// + always check ownership, not just role
TOTP (RFC 6238)
import { authenticator } from 'otplib';
const secret = authenticator.generateSecret();
const uri = authenticator.keyuri(email, 'MyApp', secret); // QR
const ok = authenticator.verify({ token, secret });
Factors
| Category | Example |
| Know | Password, PIN |
| Have | TOTP app, passkey, hardware key |
| Are | Fingerprint, face |
Attacks & Mitigations
| Attack | Mitigation |
| CSRF | SameSite + anti-CSRF token, check Origin |
| XSS | Output encoding, CSP, HttpOnly cookies |
| Session fixation | Regenerate session ID on login |
| Credential stuffing | Rate limit, MFA, breached-pw check |
| Brute force | Slow hash, throttle, backoff |
| Token theft | Short expiry, rotation, TLS |
| JWT alg confusion | Pin algorithms, reject alg:none |