Back
Interactive Explainer

Auth & Authorization: Securing Backend Systems

Authentication proves who you are. Authorization proves what you can do. Both are hard.

🎯Key Takeaways
Authentication (who you are) and authorization (what you can do) are separate concerns — don't conflate them.
Use RS256 (asymmetric JWT signing) in multi-service architectures so services can verify tokens without the signing key.
JWT payloads are base64url encoded, NOT encrypted. Never store sensitive data in claims.
Authorization Code + PKCE is the modern OAuth flow for user-facing applications.
Use RBAC for most applications. Consider ReBAC (Google Zanzibar model) for complex relationship-based permissions.
Return 401 for missing/invalid identity. Return 403 for valid identity with insufficient permissions.

Auth & Authorization: Securing Backend Systems

Authentication proves who you are. Authorization proves what you can do. Both are hard.

~6 min read
Be the first to complete!
What you'll learn
  • Authentication (who you are) and authorization (what you can do) are separate concerns — don't conflate them.
  • Use RS256 (asymmetric JWT signing) in multi-service architectures so services can verify tokens without the signing key.
  • JWT payloads are base64url encoded, NOT encrypted. Never store sensitive data in claims.
  • Authorization Code + PKCE is the modern OAuth flow for user-facing applications.
  • Use RBAC for most applications. Consider ReBAC (Google Zanzibar model) for complex relationship-based permissions.
  • Return 401 for missing/invalid identity. Return 403 for valid identity with insufficient permissions.

Lesson outline

The Two Concepts Every Security Bug Conflates

In 2019, a security researcher found that any Twitter user could access any other user's DMs by changing a single user ID in the API request. No authentication bypass needed — just substituting your own session token with a different resource ID. This is authorization failure, not authentication failure.

ConceptQuestionMechanismExample
Authentication (AuthN)"Who are you?"Password + MFA, OAuth, certificates"Is this really Alice's session?"
Authorization (AuthZ)"What can you do?"RBAC, ABAC, ACLs, policies"Can Alice access Bob's DMs?"

OWASP #1 and #5: The Most Common Auth Bugs

#1 Broken Access Control (authorization) and #5 Security Misconfiguration are the top two web app vulnerabilities. Most security incidents aren't from exotic exploits — they're from missing authorization checks.

JWTs: The Standard Bearer (and Its Pitfalls)

JSON Web Tokens are the de facto standard for stateless authentication in APIs. Understanding them deeply prevents critical security vulnerabilities.

JWT Anatomy

  • 🔵Header{"alg": "HS256", "typ": "JWT"} — base64url encoded. Declares the signing algorithm.
  • 🟢Payload (Claims){"sub": "user-123", "exp": 1735689600, "roles": ["admin"]} — base64url encoded. NOT encrypted.
  • 🔴SignatureHMAC-SHA256(header + "." + payload, secret) — cryptographic proof the server created this token.

JWT Payload Is NOT Encrypted

JWTs are base64url-encoded, not encrypted. Anyone can decode the payload and read the contents. Never store sensitive data (passwords, PII, credit card numbers) in JWT claims. Only store non-sensitive identifiers.

JWT Vulnerabilities You Must Know

1

alg=none attack: Old libraries accepted tokens with algorithm set to "none" (no signature). Always validate the algorithm in your library.

2

HS256 vs RS256: HS256 uses a shared secret (symmetric). RS256 uses public/private key (asymmetric). Use RS256 for multi-service architectures so services can verify without knowing the signing key.

3

JWT expiry: Short-lived tokens (15 min) + refresh tokens is the production pattern. Long-lived tokens can't be revoked without a blocklist.

4

Key rotation: Rotate signing keys regularly. Use key IDs (kid) in the header so services know which key to use for verification.

jwt-auth.ts
1// Production JWT implementation with Node.js
2import jwt from 'jsonwebtoken';
3import { Request, Response, NextFunction } from 'express';
4
5// ✅ Use RS256 (asymmetric) for multi-service architectures
6const JWT_PRIVATE_KEY = process.env.JWT_PRIVATE_KEY!; // Only auth service has this
Private key signs, public key verifies. Only auth service needs private key
7const JWT_PUBLIC_KEY = process.env.JWT_PUBLIC_KEY!; // All services can verify
8
9interface JWTPayload {
10 sub: string; // subject = user ID
11 roles: string[];
12 iat: number; // issued at
13 exp: number; // expiration
14}
15
16// Sign token — only call from auth service
17function signToken(userId: string, roles: string[]): string {
18 return jwt.sign(
RS256 prevents the alg:none attack and enables services to verify without the signing secret
19 { sub: userId, roles },
20 JWT_PRIVATE_KEY,
15 minutes is the production standard for access tokens. Pair with refresh tokens
21 {
22 algorithm: 'RS256',
23 expiresIn: '15m', // Short-lived: 15 minutes
24 issuer: 'auth-service',
25 }
26 );
27}
28
29// Verify middleware — used by all services
30function requireAuth(req: Request, res: Response, next: NextFunction) {
31 const token = req.headers.authorization?.replace('Bearer ', '');
Explicitly whitelist algorithms. Never let the client choose the algorithm
32 if (!token) return res.status(401).json({ error: 'Missing token' });
33
34 try {
35 const payload = jwt.verify(token, JWT_PUBLIC_KEY, {
36 algorithms: ['RS256'], // Explicitly allow ONLY RS256 — prevent alg:none attack
37 issuer: 'auth-service',
38 }) as JWTPayload;
39
40 req.user = { id: payload.sub, roles: payload.roles };
41 next();
42 } catch (err) {
43 return res.status(401).json({ error: 'Invalid or expired token' });
401 = unauthenticated (no valid identity). 403 = unauthorized (valid identity, wrong permissions)
44 }
45}
46
47// Authorization: role-based check
48function requireRole(role: string) {
49 return (req: Request, res: Response, next: NextFunction) => {
50 if (!req.user?.roles.includes(role)) {
51 return res.status(403).json({ error: 'Insufficient permissions' });
52 }
53 next();
54 };
55}
56
57// Usage
58router.delete('/admin/users/:id',
59 requireAuth, // 401 if no valid token
60 requireRole('admin'), // 403 if not admin
61 deleteUserHandler
62);

OAuth 2.0 and OIDC: The Industry Standard Delegated Auth

OAuth 2.0 is an authorization framework. OpenID Connect (OIDC) is an authentication layer built on top of OAuth 2.0. Understanding the difference prevents building broken "Login with Google" implementations.

FlowUse CaseHow It Works
Authorization Code + PKCEWeb apps, mobile apps (RECOMMENDED)Exchange authorization code for tokens. PKCE prevents code interception attacks.
Client CredentialsMachine-to-machine (M2M)Client ID + Secret → access token. No user involved.
Implicit (DEPRECATED)Old SPA patternToken returned directly in URL. Vulnerable to leakage. Never use for new projects.
Device FlowSmart TVs, CLIsUser authorizes on phone/computer while device polls for token.

The Modern Auth Stack

Authorization Code + PKCE for user-facing apps. Client Credentials for service-to-service. Use an identity provider (Auth0, Cognito, Firebase Auth) instead of building your own — auth is hard to get right and catastrophic when wrong.

OAuth Authorization Code + PKCE Flow

1

App generates code_verifier (random string) and code_challenge (SHA256 hash)

2

App redirects user to Identity Provider with code_challenge

3

User authenticates with Identity Provider (Google, GitHub, etc.)

4

Identity Provider redirects back with authorization code

5

App exchanges code + code_verifier for access token (verifier proves it's the same app)

6

App uses access token for API calls

7

When access token expires, app uses refresh token to get a new one

Authorization Models: RBAC, ABAC, and Beyond

ModelHow It WorksBest ForLimitation
RBAC (Role-Based)User has roles; roles have permissionsMost applications — simple, fast, auditableRole explosion at scale (1000+ roles)
ABAC (Attribute-Based)Policies based on attributes of user, resource, environmentComplex enterprise, multi-tenant SaaSHard to audit, complex policy language
ReBAC (Relationship-Based)Permissions based on relationship between user and resourceGoogle Docs, GitHub — "owner can edit, viewer can read"Complex graph traversal at scale
Policy-as-Code (OPA)Rego policies evaluated at runtimeKubernetes RBAC, API gateways, microservicesLearning curve, policy testing discipline required

Google Zanzibar: How Google Scaled Authorization

Google's Zanzibar system (used by Drive, YouTube, Maps) uses relationship-based access control (ReBAC). A shared Google Doc's "viewer" permission is stored as a tuple: (document:123, viewer, user:456). Zanzibar evaluates millions of such checks per second. Open-source implementation: OpenFGA (by Okta).

rbac-middleware.ts
1// RBAC with resource-level ownership check
2// Combines role-based AND resource ownership authorization
3
4interface User {
5 id: string;
6 roles: ('admin' | 'editor' | 'viewer')[];
7}
8
9// Permission matrix
10const PERMISSIONS: Record<string, string[]> = {
Centralize permissions in one place — never scatter permission checks through code
11 'admin': ['read', 'write', 'delete', 'manage'],
12 'editor': ['read', 'write'],
13 'viewer': ['read'],
14};
15
16function hasPermission(user: User, permission: string): boolean {
17 return user.roles.some(role => PERMISSIONS[role]?.includes(permission));
18}
19
20// Resource-level authorization: "can this user act on THIS resource?"
21async function authorizeResource(
22 user: User,
23 resourceId: string,
24 action: 'read' | 'write' | 'delete'
Always check admin role first as a fast path
25): Promise<boolean> {
26 // Admin can do anything
27 if (user.roles.includes('admin')) return true;
28
29 // Otherwise check ownership
30 const resource = await db.resources.findById(resourceId);
31 if (!resource) return false;
Resource ownership check: user can modify their own resources without needing elevated roles
32
33 // Owner can do anything with their resource
34 if (resource.ownerId === user.id) return true;
35
36 // Non-owners need explicit permission + action allowed
37 return hasPermission(user, action);
38}
39
40// Route guard
41router.delete('/posts/:id',
42 requireAuth,
43 async (req, res, next) => {
44 const allowed = await authorizeResource(req.user, req.params.id, 'delete');
45 if (!allowed) return res.status(403).json({ error: 'Forbidden' });
46 next();
47 },
48 deletePostHandler
49);
How this might come up in interviews

Auth questions test both security knowledge and system design thinking. Interviewers want to see that you know JWT internals, understand OAuth flows, and can design authorization that scales.

Common questions:

  • How would you implement authentication for a multi-service architecture?
  • What is the difference between JWT HS256 and RS256? When would you use each?
  • How do you handle token revocation with stateless JWTs?
  • Design the authorization system for a multi-tenant SaaS application

Strong answers include:

  • Mentions PKCE unprompted when discussing OAuth
  • Discusses token revocation strategies (blocklist, short expiry + refresh)
  • Knows the alg:none JWT attack
  • Understands 401 vs 403 distinction

Red flags:

  • Stores passwords in plain text or with MD5/SHA1
  • Doesn't know what OAuth 2.0 authorization code flow does
  • Confuses authentication and authorization
  • Uses symmetric signing (HS256) across multiple services

Quick check · Auth & Authorization: Securing Backend Systems

1 / 3

A user with role "editor" tries to delete a post they didn't create. Your API returns 200 OK. What type of vulnerability is this?

Key takeaways

  • Authentication (who you are) and authorization (what you can do) are separate concerns — don't conflate them.
  • Use RS256 (asymmetric JWT signing) in multi-service architectures so services can verify tokens without the signing key.
  • JWT payloads are base64url encoded, NOT encrypted. Never store sensitive data in claims.
  • Authorization Code + PKCE is the modern OAuth flow for user-facing applications.
  • Use RBAC for most applications. Consider ReBAC (Google Zanzibar model) for complex relationship-based permissions.
  • Return 401 for missing/invalid identity. Return 403 for valid identity with insufficient permissions.

From the books

OAuth 2.0 in ActionJustin Richer, Antonio Sanso (2017)

Chapters 1-3: OAuth Fundamentals

OAuth 2.0 is a delegation framework, not an authentication protocol. OIDC adds authentication on top. Confusing the two leads to security vulnerabilities.

Ready to see how this works in the cloud?

Switch to Career Paths for structured paths (e.g. Developer, DevOps) and provider-specific lessons.

View role-based paths

Sign in to track your progress and mark lessons complete.

Discussion

Questions? Discuss in the community or start a thread below.

Join Discord

In-app Q&A

Sign in to start or join a thread.