skip to content

A per-request interception step redirects requests carrying no session cookie to the sign-in page — why is that not authorisation?

level: seniorimportance: must knowfreq 68%

answer

  1. presence is not validity
  2. identity is not permission
  3. the record is not known yet
  4. covers only what the matcher selects
  5. the write is the check nobody skips

basics

~20 s

A cookie's presence is not a verified session and says nothing about what this visitor may do with this record. Treat the redirect as convenience; enforce the real check in the route's data step and every write.

solid answer

~50 s

The step sees an opaque string in a header. It has not checked that the value is still valid, that it was not revoked or replayed, or that the person it names may read the thing this URL is about — the record's identity comes from routing and its owner comes from data, neither of which exists at this station. Verifying properly usually means a lookup, and a lookup per request is the cost this position exists to avoid. Coverage is the second problem: the gate applies to exactly what the matcher selects, so a section's data endpoints, later-added paths, and background regeneration requests can reach the same information without passing it. Keep the redirect for what it is good at — not rendering a page the visitor will be bounced off — and put the decision that must not be bypassed next to the data it protects.

go deeper

for a junior

Remember that seeing a cookie only tells you a header was sent; it is not proof of a valid session and says nothing about what the visitor is allowed to see.

for a middle

Explain the three gaps in order — presence to validity, identity to permission, permission to this specific record — and why the last is impossible at a station that runs before routing.

for a senior

Lead with coverage: name the paths that never meet the step, and place the enforceable check in the route's data step and on every write.

for a principal

Set the standard that permission decisions live in one shared place next to the data, and that the front-door redirect is documented as user experience so nobody later mistakes it for the control.

## What the step can actually establish At this station the request is still an envelope. The step can see that a `Cookie` header contains a name it recognises and that the value has a plausible shape. That is genuinely useful, and it is cheap. But between "a cookie is present" and "this visitor may perform this operation on this record" there are three separate gaps: 1. **Validity.** The value may be expired, revoked, or copied from another browser. Establishing otherwise means either verifying a self-contained signed value, which needs the right primitives in a restricted runtime and still cannot know about revocation, or consulting the store that issued it — a round trip on a path that is supposed to be fast. 2. **Identity to subject.** Even a perfectly valid session names a visitor, not a permission. Nothing in the envelope says what that visitor is allowed to reach. 3. **Subject to object.** The thing being protected is usually a specific record, and which record this URL is about is the output of route resolution, while who owns it is the output of a data read. Both happen after this station. ## Why the gate is not a boundary Coverage is the failure that actually bites, and it is quiet: - **Paths the matcher does not select.** The rule applies to exactly the selected set; a section's non-document endpoints, a nested data path used by client-side navigation, or a page added later under a different prefix are all served without meeting it. - **Requests that do not arrive from a browser at all.** Background regeneration of a cached page, internal calls and scheduled work can produce or serve the same content on a path that carries no cookie by design. - **Cached answers.** A page rendered once for someone who passed the gate can be served to someone who did not, unless the response was explicitly made per-visitor. - **A cookie that is present but worthless.** Any client can send a cookie header with the expected name; presence is trivially forged, and the step is not checking anything else. Each of these is a way for the information to be reached without the redirect ever running. A rule that can be walked around by using a different URL is a routing convenience, not an enforcement point. ## Where each decision belongs | Layer | What it decides | Cost profile | |---|---|---| | Interception step | "This looks signed out — send it to the sign-in page instead of rendering" | Envelope only, must stay fast | | The route's data step | "This is the real visitor, and this record is theirs to read" | Already doing a lookup; the check rides along | | The write itself | "This mutation is permitted, for this record, right now" | The last point before state changes, and the one no caller can skip | The write is the non-negotiable one. Reads leak; writes destroy, and a write is reachable by anything that can send a request, including code paths that never render a page. A check that exists only at the front door has no effect on a write invoked directly. ## What the gate is genuinely good for Keeping it is right — just for honest reasons: 1. **Avoiding wasted rendering.** Bouncing a signed-out request before the route runs saves a render and a data read that would have been thrown away. 2. **One place for the redirect.** The destination, the return path and the behaviour of the whole section live in one file instead of in every route. 3. **A fast negative.** The overwhelmingly common case — no cookie at all — is answered from the envelope with no lookup. ## The trap to name in an interview The tempting fix is to make the step do the real check: verify the credential, load the visitor, check the permission. That drags a dependency call onto a station every matched request crosses, inside a unit with tight limits, and it still cannot answer the record-level question because the record is not known yet. The duplication people are trying to avoid is unavoidable — and it is not really duplication, because the two checks answer different questions. The cheap one decides where to send a request; the real one decides whether to hand over data. Meta-frameworks differ in how much help they give with the second check — some offer a shared wrapper every route's data step calls, others leave it to convention — but none of them make the front-door redirect sufficient on its own.

  • Why not verify the credential properly inside the step?
    Verification either needs a lookup against the issuing store, which puts a dependency call on a path every matched request crosses, or it is limited to checking a signature, which cannot see revocation. Even perfect verification answers only who the visitor is, not whether this record is theirs — and that record is not known until routing and a data read have happened.
  • If the real check lives in the route anyway, is the redirect worth keeping?
    Yes, for what it actually does: it stops an obviously signed-out request before the route renders and reads data that would be discarded, and it keeps the destination and return-path behaviour of a whole section in one place. Just do not describe it as the thing that protects the data.
  • How would you keep the two checks from drifting apart?
    Express the real decision once as a function the route's data step and every write both call, and let the interception step make only the coarse envelope decision. Then the gate and the enforcement cannot disagree about permissions, because only one of them is deciding permissions at all.

saying these in an interview costs you the question

  • Treats a present cookie as a verified session
  • Says the route needs no check because the front door has one
  • Loads the visitor from the database on every matched request
  • Forgets that writes are reachable without rendering a page
  • Assumes the matcher covers every path that exposes the data
  • Believes a cached page can never reach someone who skipped the gate