SYSTEM DESIGN · CONCEPTS · RUNNING IT IN PRODUCTION · EPISODE 38

Security: Auth, OAuth, JWT, Encryption

The security basics every system design needs: authentication vs authorisation, storing passwords with slow hashes, sessions vs JWT access and refresh tokens, OAuth 2.0 and "Sign in with Google", encryption in transit and at rest, secrets management, least privilege, and common attacks with their defences.

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
1 / 10

Press play to hear the narration, or step through at your own pace. Every picture here is the same one used in the YouTube video.

Notes

AuthN vs AuthZ

Two separate questions. Authentication asks who you are: a password, a passkey, a one-time code. Authorisation asks what you're allowed to do: can user forty-two edit order nine? Authentication happens at login; authorisation must be checked on every single request, on the server, never trusted from the client.

Two different questions
  • authentication (authN):
  • who are you?
  • password, passkey, OTP, SSO
  • authorisation (authZ):
  • what may you do?
  • roles, permissions, ownership:
  • can user 42 edit order 9?
  • check authZ on EVERY request,
  • on the server

Passwords

Never store passwords, not even encrypted. Store a slow, salted hash, using bcrypt, scrypt or argon2. The salt makes every hash unique, and the slowness, around a tenth of a second per guess, turns cracking a leaked database from minutes into years. Add rate limits on login and two-factor authentication.

Storing passwords
never: plain text
never: md5 / sha256 alone

use a slow, salted hash:
  bcrypt, scrypt, argon2id
  hash = argon2(password, salt)

slow = ~100 ms per guess
→ a leaked DB takes years
  to crack, not minutes
+ rate-limit logins, add 2FA

Tokens

After login, the client needs to prove who it is on each request. Either a random session id in a cookie, with the data on the server, easy to revoke. Or a signed token like a JWT that any service can verify without a lookup, but that's hard to revoke, so keep it short-lived, about fifteen minutes, with a long-lived refresh token you can revoke. Cookies should be HttpOnly, Secure and SameSite.

Sessions vs JWTs
  • session id in a cookie,
  • data on the server
  • + easy to revoke
  • JWT: signed claims, no lookup
  • + stateless, works across
  • services
  • − hard to revoke → keep it
  • short (≈15 min) + a refresh
  • token you CAN revoke
  • cookies: HttpOnly, Secure, SameSite

OAuth

OAuth is how 'Sign in with Google' works without the app ever seeing your Google password. The app redirects you to Google, you log in and consent there, Google sends you back with a one-time code, and the app exchanges that code for tokens, server to server. OAuth handles delegated access; OpenID Connect adds identity on top.

OAuth 2.0 / OpenID Connect
  • "Sign in with Google":
  • 1. app redirects you to Google
  • 2. you log in and consent there
  • 3. Google redirects back with
  • a one-time code
  • 4. app exchanges the code for
  • tokens (server to server)
  • OAuth: delegated access
  • OIDC: adds identity (id token)
  • use PKCE for mobile / SPA

Encryption

Encrypt data in transit with TLS everywhere, including between your own services with mutual TLS. Encrypt it at rest: disks, databases, backups and object storage, with keys held in a key management service and rotated. For extra-sensitive fields like card numbers, use field-level encryption or tokenisation.

Encryption
  • in transit: TLS everywhere
  • (HTTPS, also between services:
  • mTLS)
  • at rest: disks, DB, backups,
  • object storage encrypted (AES)
  • keys in a KMS, rotated
  • extra-sensitive fields
  • (card numbers, Aadhaar):
  • field-level encryption or
  • tokenisation

Secrets

Database passwords and API keys never belong in code, Git or container images. Keep them in a secrets manager and inject them at runtime, with rotation. Apply least privilege: each service gets only the permissions it needs, production access is limited and every access is logged.

Secrets and least privilege
  • no API keys in code, Git,
  • or Docker images
  • → secrets manager (Vault, AWS
  • Secrets Manager), injected
  • at runtime, rotated
  • least privilege: each service
  • gets only the permissions
  • it needs
  • separate prod access, audit logs

Attacks

Know the common attacks and their fixes. SQL injection: always use parameterised queries. Cross-site scripting: escape output and set a content security policy. Cross-site request forgery: SameSite cookies or tokens. Broken access control, the most common one: check ownership on every request. And rate limits, a firewall and a CDN against brute force and floods.

Common attacks
  • SQL injection → parameterised
  • queries, never string concat
  • XSS → escape output, CSP
  • CSRF → SameSite cookies, tokens
  • broken access control →
  • check ownership every request
  • brute force → rate limits, 2FA
  • DDoS → CDN, WAF, rate limits
  • outdated libraries → patch

Say it like this

In an interview: an auth service issues short-lived access tokens with refresh tokens, or you use single sign-on via OpenID Connect. The API gateway verifies tokens, and each service checks permissions on the resource. Hash passwords with argon2 or bcrypt, use TLS everywhere, encrypt at rest with managed keys, keep secrets in a manager, and rate-limit.

In the interview
  • auth service issues short JWT
  • + refresh token; or OIDC SSO
  • API gateway verifies tokens
  • each service checks permissions
  • passwords: argon2/bcrypt
  • TLS everywhere, mTLS inside
  • encryption at rest, KMS keys
  • secrets manager, least privilege
  • rate limits, audit logs

Interview questions

What is the difference between authentication and authorisation?

Authentication verifies identity (who you are). Authorisation decides what an authenticated identity may do (which resources and actions), and must be checked server-side on every request.

How should passwords be stored?

As salted hashes produced by a deliberately slow algorithm such as argon2id, bcrypt or scrypt, never in plain text, reversible encryption or fast hashes like MD5 or SHA-256 alone.

What are the pros and cons of JWTs?

They are self-contained and verifiable by any service without a database lookup. But they are hard to revoke before expiry and can carry stale permissions, so access tokens are kept short-lived with revocable refresh tokens.

How does OAuth 2.0 authorization code flow work?

The app redirects the user to the authorisation server, the user authenticates and consents there, the server redirects back with a short-lived code, and the app exchanges the code (with PKCE or a client secret) for access and refresh tokens.

What is the difference between OAuth and OpenID Connect?

OAuth 2.0 grants delegated access to APIs. OpenID Connect builds on OAuth to provide authentication, returning an ID token with information about the signed-in user.

What does encryption in transit and at rest mean?

In transit: data moving over the network is protected with TLS (HTTPS, mTLS between services). At rest: stored data on disks, databases, backups and object storage is encrypted, with keys managed in a KMS.

How do you prevent SQL injection?

Use parameterised queries or prepared statements (or a safe ORM) so user input is never concatenated into SQL, plus input validation and least-privilege database accounts.

What is the principle of least privilege?

Each user, service and process gets only the minimum permissions it needs, limiting the damage if it is compromised.