Skip to content

Authentication Cheat Sheet

Authentication verifies identity; authorization decides access. Web apps use sessions or JWTs, secure cookies, OAuth for third-party login, and hashed passwords never stored in plain text.

How to use this Authentication cheat sheet

Session auth stores server-side state with a session ID in an HttpOnly cookie. JWTs embed claims signed by the server; access tokens are short-lived with refresh tokens rotated in secure storage. Cookie flags Secure, HttpOnly, and SameSite reduce XSS and CSRF risk.

OAuth 2.0 delegates login to providers (Google, GitHub) via authorization code flow with PKCE for SPAs. CSRF tokens protect cookie-based forms. Passwords use bcrypt or Argon2 with per-user salt; never roll your own crypto.

Quick Authentication example

// Set session cookie after login
res.cookie('sessionId', session.id, {
  httpOnly: true,
  secure: true,
  sameSite: 'lax',
  maxAge: 24 * 60 * 60 * 1000,
  path: '/',
});

// Verify JWT access token
const payload = jwt.verify(token, process.env.JWT_SECRET, {
  algorithms: ['HS256'],
  issuer: 'https://api.example.com',
});

Sessions vs JWT

Aspect Session JWT
Storage Server store (Redis/DB) Client bearer token or cookie
Revocation Delete session server-side Hard until expiry; use blocklist or short TTL
Scale Sticky session or shared store Stateless verification with secret/public key
Size Small cookie (session id) Larger payload with claims
XSS impact HttpOnly cookie not readable by JS localStorage JWT stolen by XSS
Best for Traditional web apps APIs, mobile, microservices
Refresh pattern Extend session sliding window Short access + long refresh token
Logout Destroy session record Discard tokens + revoke refresh server-side

Cookie Flags & CSRF

Flag / Pattern Example Notes
HttpOnly httpOnly: true JS cannot read cookie—mitigates XSS theft
Secure secure: true HTTPS only
SameSite sameSite: "lax" or "strict" CSRF mitigation; None requires Secure
Path / Domain path: "/" Limit cookie scope narrowly when possible
CSRF token <input type="hidden" name="_csrf" value="..."> Validate on state-changing requests
Double-submit Cookie + header must match SPA with SameSite=None APIs
Origin check Validate Origin/Referer header Additional CSRF layer
CORS Credentials + specific origins Never Access-Control-Allow-Origin: * with cookies

OAuth & Password Hashing

Topic Example Notes
Auth code + PKCE code_challenge S256 for SPAs Public clients cannot keep secrets
Redirect URI Exact match registered Prevent code interception
State param Random state validated on callback CSRF on OAuth redirect
Scopes openid profile email Request minimum scopes needed
ID token OIDC JWT with user claims Verify signature and aud/iss
bcrypt bcrypt.hash(pw, 12) Adaptive cost factor 10–12+
Argon2id Winner of password hashing competition Preferred for new systems
Never MD5/SHA1 for passwords Use dedicated password KDF only

Refresh Tokens & Token Rotation

Pattern Example Notes
Access TTL 5–15 minutes Limits exposure window
Refresh TTL Days to weeks Stored HttpOnly or secure rotation store
Rotation New refresh on each use Detect reuse → revoke family
Storage SPA HttpOnly cookie for refresh Avoid localStorage for tokens
Mobile Secure enclave / Keychain Platform secure storage APIs
Revocation list Redis set of jti Invalidate before natural expiry
Silent refresh POST /token with refresh cookie Renew access without re-login
MFA step-up Require MFA for sensitive actions Even with valid session/JWT

OAuth 2.0 authorization code with PKCE

const verifier = base64url(crypto.randomBytes(32));
const challenge = base64url(sha256(verifier));
const authUrl = new URL('https://provider/oauth/authorize');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', CLIENT_ID);
authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
authUrl.searchParams.set('code_challenge', challenge);
authUrl.searchParams.set('code_challenge_method', 'S256');
authUrl.searchParams.set('state', randomState);

Exchange code server-side with code_verifier; never expose client secret in SPA.

bcrypt password verify

import bcrypt from 'bcrypt';

const hash = await bcrypt.hash(password, 12);
const ok = await bcrypt.compare(loginPassword, storedHash);
if (!ok) throw new UnauthorizedError();

Store only hash; use constant-time compare built into bcrypt.compare.

CSRF middleware pattern (Express)

import csrf from 'csurf';
const csrfProtection = csrf({ cookie: { httpOnly: true, sameSite: 'strict' } });

app.get('/form', csrfProtection, (req, res) => {
  res.render('form', { csrfToken: req.csrfToken() });
});
app.post('/form', csrfProtection, handler);

Pair CSRF tokens with SameSite cookies for defense in depth.

Common mistakes

  • Storing JWTs in localStorage where any XSS script can exfiltrate them.
  • Using SameSite=None without Secure flag on cookies.
  • Skipping PKCE on SPA OAuth flows because the client is public.
  • Storing passwords with fast hashes (SHA256) instead of bcrypt/Argon2.

Key takeaways

  • Sessions for traditional apps; short-lived JWTs plus refresh for APIs.
  • HttpOnly, Secure, SameSite cookies and CSRF tokens protect cookie-based auth.
  • OAuth authorization code with PKCE for third-party login in browsers.
  • Hash passwords with bcrypt/Argon2; rotate refresh tokens and detect reuse.

Pro Tip

Use a dedicated auth library (Passport, Auth.js, or your cloud IdP SDK) instead of assembling JWT parsing, cookie flags, and OAuth flows from blog snippets.