Fundamentals
Security
Authentication vs. authorization, sessions vs. JWTs, SSRF, secrets management, and least privilege.
Security rarely gets its own deep dive in a 45-minute interview, but it shows up constantly as a two-minute question tacked onto the end of another one — "how would you authenticate this," "what stops someone from abusing that endpoint." Having crisp, short answers ready is worth more here than anywhere else in this track.
Authentication vs. authorization
Two different questions, often conflated. Authentication answers "who is
this" — logging in, verifying a token. Authorization answers "what is this
identity allowed to do" — a logged-in user might still be forbidden from
deleting someone else's post. A system that checks authentication
carefully but skips authorization on individual resources is a common,
real vulnerability class (an authenticated user hitting DELETE /posts/:id for a post that isn't theirs) — naming that these are separate
checks, not one, is worth doing explicitly rather than assuming it's
obvious.
Sessions vs. tokens
| Session (cookie + server-side store) | JWT (self-contained token) | |
|---|---|---|
| Revocation | Immediate — delete the server-side row | Hard — the token is valid until it expires, unless you maintain a blocklist (which reintroduces server-side state anyway) |
| Server state | Requires a shared store (e.g. Redis) if there's more than one server | None needed to verify the token — any server with the signing key can check it |
| Good fit | Most first-party web apps | Service-to-service calls, or a case where avoiding a shared session store genuinely matters |
The trade-off in one line: a session is easy to revoke and needs shared state; a JWT needs no shared state to verify but is hard to revoke early. Short JWT expiries (issue a new one every few minutes, backed by a longer-lived refresh token) is the common way to get most of both — bounded exposure if a token leaks, without a session store on the hot path.
Transport security
TLS terminates the "is this connection actually private and unmodified" question at the network layer — assume it everywhere and don't reinvent it at the application layer. The detail worth having ready: TLS should be terminated as close to the actual backend as reasonable, not just at the public edge — internal service-to-service traffic inside a private network is still worth encrypting if the blast radius of one compromised internal host matters, which in most real production environments it does.
Cross-site scripting (XSS) and cross-site request forgery (CSRF)
Two different attacks that get confused for each other. XSS happens
when attacker-controlled input gets rendered as executable script in
another user's browser — a comment field that stores <script> verbatim
and a page that renders it unescaped lets that script run with the
victim's session. The fix is escaping output by default (nearly every
modern frontend framework does this automatically) and never trusting
raw-HTML rendering with unsanitized input. CSRF is different: it
doesn't inject anything, it makes the victim's browser submit a request
the victim never intended, using credentials the browser attaches
automatically — a malicious page with a hidden auto-submitting form works
because the browser sends the victim's session cookie regardless of which
site the request originated from. The standard fix is a CSRF token — a
value the legitimate page embeds and the server checks, that an attacker's
page has no way to know — plus setting cookies SameSite=Lax or Strict,
which stops the browser from attaching them to cross-site requests at all.
Injection
SQL injection is the classic version — building a query by concatenating
raw user input lets an input like ' OR '1'='1 change the query's meaning
entirely. Parameterized queries (or an ORM that generates them) close this
off by sending the input as data, never as part of the query text. The
same class of bug exists for NoSQL: passing an unsanitized JSON body
straight into a MongoDB query lets an operator like {"$gt": ""} bypass
an equality check the developer assumed was a plain string comparison.
Rate limiting and DoS as a security concern, not just a fairness one
The Rate Limiter case study frames rate limiting as fairness between clients — it's also a security control: an unauthenticated login endpoint with no rate limit is a standing invitation to brute-force credential guessing. Interviewers sometimes probe this directly: "what stops someone from trying every password against this endpoint" is a rate-limiting question wearing a security hat.
SSRF: when the server fetches a URL on someone else's behalf
Any design where the server fetches a URL supplied by a client — the
Web Crawler case study is
a design built entirely around doing exactly this — has to consider
server-side request forgery: a malicious input pointing the server at an
internal-only address (http://169.254.169.254/, a common cloud metadata
endpoint, or an internal admin service with no auth because it "isn't
public") instead of a real external page. The standard mitigation is an
allowlist or explicit block on private/internal IP ranges before the
server ever makes the outbound request, not just validating that the input
"looks like a URL."
Secrets management
An API key or database credential belongs in a secrets manager (or, at minimum, an environment variable injected at deploy time) — never committed to source, and never returned in a response or log line. The interview-relevant version of this: if a design's API returns any kind of internal token or credential to a client, that's worth flagging as a design smell even if the interviewer didn't ask about it directly.
Encryption at rest
TLS protects data in transit; it says nothing about data sitting in a database or a backup. Encryption at rest means the data on disk is unreadable without the decryption key even if the disk itself is compromised or a backup is exfiltrated — most managed databases (RDS, DynamoDB) offer this as a checkbox rather than something to build, so the interview-relevant version is knowing to turn it on for anything sensitive (payment details, personal data) and naming that the encryption key itself needs its own access control, separate from the data it protects.
Least privilege and defense in depth
A service should hold only the permissions it actually needs — a notification worker that only sends emails shouldn't also have write access to the primary user database, even if it's convenient to grant broadly upfront. Defense in depth is the same idea at the system level: don't rely on a single control (the login page's rate limiter, say) as the only thing standing between an attacker and a bad outcome — authorization checks at the resource level, network-level segmentation, and input validation should each independently reduce risk, so that one control failing doesn't mean the whole system fails with it.