Authentication & Authorization
Sessions vs JWTs. OAuth flows. RBAC done right. Why bcrypt is non-negotiable.
Authentication vs Authorization
Authentication (AuthN) — WHO are you?
Proving identity. "I am Alice."
Done via: passwords, tokens, certificates, biometrics.
Authorization (AuthZ) — WHAT can you do?
Checking permissions after identity is established.
"Alice is allowed to read this document, but not delete it."
Common mistake: conflating them. Authentication failing → 401 Unauthorized. Authorization failing → 403 Forbidden. These are different HTTP status codes for a reason.
Sessions vs Tokens
Sessions (server-side state):
1. User logs in → server creates session, stores in DB/Redis
2. Server gives client a session ID (cookie)
3. Every request: client sends cookie, server looks up session in DB
Pros: Easy to invalidate. Server controls state.
Cons: Doesn't scale horizontally without shared session store.
JWTs (stateless tokens):
1. User logs in → server creates signed token containing claims
2. Client stores token (localStorage or cookie)
3. Every request: client sends token, server validates signature
Pros: Stateless, scales infinitely, works across services.
Cons: Can't be revoked without a blocklist. Tokens valid until expiry.
Production pattern: Use short-lived JWTs (15 min) + long-lived refresh tokens (7 days) stored in httpOnly cookies.
JWT Deep Dive
A JWT has three base64url-encoded parts: Header.Payload.Signature
Header: {"alg": "HS256", "typ": "JWT"}
Payload: {"sub": "user_123", "role": "admin", "iat": 1699000000, "exp": 1699000900}
Signature: HMAC-SHA256(base64(header) + "." + base64(payload), secret)
The server validates by re-computing the signature and checking it matches. Tampering with the payload breaks the signature.
NEVER store sensitive data in the payload — it's base64 encoded, not encrypted. Anyone can decode and read it.
Important claims:
• sub — subject (user ID)
• iat — issued at
• exp — expiration
• iss — issuer
• aud — audience
Password Hashing
NEVER store plain-text passwords. NEVER use MD5 or SHA-1 for passwords.
Use bcrypt, Argon2, or scrypt — these are slow by design (hardened against GPU brute-force).
bcrypt flow:
1. User sets password "hunter2"
2. bcrypt generates a random salt
3. bcrypt(password + salt) → hash (takes ~100ms intentionally)
4. Store the hash, discard the password
On login:
1. User sends "hunter2"
2. Retrieve hash from DB
3. bcrypt.compare("hunter2", storedHash) → true/false
bcrypt stores the salt in the hash itself — no separate column needed.
Cost factor: higher = slower = more secure. 10-12 is standard. Test on your hardware.
OAuth 2.0 & SSO
OAuth 2.0 is not authentication — it's authorization delegation. "Allow this app to access my Google data."
Key roles:
• Resource Owner — the user
• Client — your app
• Authorization Server — Google/GitHub/etc.
• Resource Server — the API with the data
Authorization Code Flow (for web apps):
1. User clicks "Login with Google"
2. Redirect to Google with your client_id + redirect_uri
3. User grants permission
4. Google redirects back with ?code=xyz
5. Your server exchanges code for access_token + id_token (server-to-server)
6. Verify id_token, extract user info, create session
OpenID Connect (OIDC) adds identity on top of OAuth 2.0. The id_token is a JWT with user info. This IS authentication.
Never use the Implicit Flow (deprecated). Use PKCE for mobile/SPA apps.
Role-Based Access Control (RBAC)
RBAC assigns permissions to roles, then assigns roles to users.
Roles: user, moderator, admin, super_admin
Permissions: read:posts, create:posts, delete:any_post, manage:users
User has roles → roles have permissions → check if permission is granted.
Implementation:
function requirePermission(permission) {
return (req, res, next) => {
const userPermissions = getPermissions(req.user.roles);
if (!userPermissions.includes(permission)) {
return res.status(403).json({ error: "Forbidden" });
}
next();
};
}
More granular: ABAC (Attribute-Based) — check attributes like "user owns this resource". Combine RBAC + ABAC for production systems.
The Backend from First Principles series is based on what I learnt from Sriniously's YouTube playlist — a thoughtful, framework-agnostic walk through backend engineering. If this material helped you, please go check the original out: youtube.com/@Sriniously. The notes here are my own restatement for revisiting later.