IdentityloginwalkthroughflagshipTLSsessioncookie

Follow a Login

One login traced end to end at four zoom levels — browser to TLS to password verification to session to cookie to the authorized read — naming at every stage what is sent, what boundary is crossed, what must be protected, and what an attacker would try.

▶ Run the labFollow the failure

Frame the problem

Security starts with a concrete asset, attacker capability and trust crossing.

Asset
The credential in transit, the credential at rest, the session token that replaces it, and the authorization decision that the session enables.
Attacker & capability
Different at every stage: a network observer at the TLS hop, an offline cracker at the hash, a script in the page at the cookie, a legitimate user at the authorization check.
Trust boundary
Five in sequence — network, application edge, credential store, session store, and resource authorization — each with a distinct threat and a distinct control.
AssetThreatAttack SurfaceTrust BoundaryVulnerabilityExploit PathImpactMitigationDefense in DepthResidual Risk

Level 1 and 2: the shape, then the mechanism

At the coarsest level a login is three boxes: a user submits a credential, the system verifies it, and the user is now authenticated. Every security question hides inside "verifies it" and "is now authenticated", and the value of zooming in is that each expansion introduces exactly one new asset to protect.

At the second level the mechanism appears. The browser sends the credential over TLS; the backend fetches the stored password hash for that account; a slow password-hashing function recomputes the hash from the submitted password and compares in constant time; on success the backend creates a session and returns it as a cookie. Four new assets: the credential in transit, the stored hash, the comparison itself, and the session.

Notice what has already gone wrong in many real systems by this point. The credential is logged by an access log that records POST bodies. The hash comparison uses == on strings, leaking timing. The session id is generated from a non-cryptographic random source. None of these are exotic; all are invisible at level 1.

Level 2: mechanism
email + passwordmatchBrowserTLS: confidentiality + server identityPOST /loginFetch stored hashSlow hash + constant-time compareCreate sessionSet-Cookie (HttpOnly, Secure, SameSite)
UserLLMAgentToolDataDecisionHumanGuardrail

Level 3: the authenticated request that follows

The login is only half the story; the interesting half is what the resulting cookie does on the next request. The browser attaches the cookie automatically to any request to the origin — *including requests initiated by other sites*, which is the entire basis of Cross-Site Request Forgery (CSRF). The backend looks the session id up in a session store, resolves it to a user, and only then can authorization begin.

This is where the two halves of access control meet. The session lookup answers "who"; it does not answer "may they". A system that stops here — session valid, therefore serve the resource — has the bug from Authentication vs Authorization, and it is at exactly this hop that it appears.

The session store choice has consequences that show up much later. A server-side store means revocation is a delete and takes effect immediately. A self-contained signed token means no lookup and no immediate revocation, which is the trade examined in JWT — What It Is and What It Costs.

Level 3: the wire, both directions
POST /login HTTP/1.1                          ← over TLS 1.3
Host: app.example
Content-Type: application/json

{"email":"alice@example.com","password":"••••••••"}
                                              ▲ never logged, never in a URL, never in a query string

HTTP/1.1 200 OK
Set-Cookie: sid=8Fq2...9xK; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=43200
            │                │         │       │
            │                │         │       └─ not sent on cross-site POSTs (CSRF depth)
            │                │         └───────── HTTPS only; never leaks over plaintext
            │                └─────────────────── unreadable by JavaScript (XSS depth)
            └──────────────────────────────────── 128+ bits from a CSPRNG, opaque, no user data

GET /invoices/101 HTTP/1.1
Host: app.example
Cookie: sid=8Fq2...9xK                        ← attached automatically, by any page on the origin

  server: sid → session → principal(alice, tenant A)     ← authentication
  server: invoice 101 → owner tenant B                   ← authorization input
  server: A ≠ B → 404                                     ← the decision that actually protects data

Level 4: security internals, stage by stage

At full zoom every stage has an asset, an attacker and a control, and they are all different. This table is the lesson: the same login is defended by six unrelated mechanisms, and the weakest one sets the outcome.

Two stages deserve emphasis. The stored hash is the only thing standing between a database disclosure and every user's password — including on the other services where they reused it. That is why the choice of hashing function is disproportionately important relative to how little code it is. And the authorization stage is the only one where the attacker is a legitimate user, which is why it is the one that survives every improvement to the others.

Level 4: what to protect at each stage
StageAssetAttacker & methodControl
In transitThe password itselfNetwork observer, hostile Wi-Fi, downgrade attemptTLS with certificate validation; HSTS so there is no plaintext first request
At the edgeThe password againAccess logs, error reports, APM traces capturing bodiesExplicit redaction; never accept credentials in a URL or query string
VerificationThe stored hashOffline cracking after a database disclosureA slow, salted, memory-hard password hash with a tuned work factor
ComparisonThe comparison itselfTiming differences revealing prefix matchesConstant-time comparison; uniform response time for unknown accounts
Session creationThe session idGuessing a weak id; session fixation128+ bits from a CSPRNG; issue a fresh id on login, never reuse a pre-login one
Cookie transportThe session id in the browserXSS reading it; CSRF riding it; plaintext leaking itHttpOnly, Secure, SameSite, narrow Path, short lifetime
AuthorizationThe resourceA legitimate logged-in user changing an idOwnership check against the loaded resource
AfterwardsThe audit trailDenial that the action occurredAudit event with actor, action, resource, time, source, result

Key points

  • Zooming in on a login introduces one new asset per level; six unrelated controls defend one flow.
  • The credential must never reach a log, a URL, a query string or an error report — redaction is a design requirement, not a cleanup.
  • Session id: 128+ bits from a CSPRNG, freshly issued at login, delivered with HttpOnly; Secure; SameSite.
  • Session lookup answers "who", never "may they" — authorization is a separate decision after the resource loads.
  • The stored hash is the last defence for every service where the user reused that password.

Follow a Login

Change the system and observe which assumption moves.

Follow a Login
Zoom from “logged in” to the boundaries and controls that make it true.
Data sent
Identity is claimed
Boundary
Ask which earlier guard made this trustworthy.
Possible failure
Untrusted input accepted as authority.
Defense if this fails
Limit privilege, emit an audit signal, and keep revocation/recovery possible.

Follow the attack

Safe conceptual simulation: capability → missing control → crossed boundary → asset impact.

  1. 1
    Attacker → network: attempt to observe or downgrade the connection; defeated by TLS plus HSTS, so move on.
  2. 2
    Attacker → credential store: obtain the database through some other bug; value depends entirely on the hash function used.
  3. 3
    Attacker → session: steal the cookie via XSS, or ride it via CSRF, because the browser attaches it automatically.
  4. 4
    Attacker → authorization: give up on stealing an identity and simply request another user's resource with their own valid session.
Blast radius
  • Credential compromise: this account plus every other service where the password was reused.
  • Session compromise: full access as the user for the token's lifetime, with no credential to revoke unless sessions are revocable.
  • Authorization failure: data belonging to users who did nothing wrong and cannot be notified as "compromised accounts".

Defend, detect, recover

One prevention is a single point of security failure. Layer it and make failure observable.

Prevent
  • • TLS everywhere with HSTS; no mixed content and no plaintext fallback for the login origin.
  • • Redact credentials at the logging layer by field name, not by hoping nobody logs the body.
  • • Use a modern password hash with a tuned work factor, and a constant-time comparison.
  • • Issue a new session id on every privilege change; set all three cookie attributes; keep the lifetime short and refresh on activity.
  • • Enforce resource-level authorization after loading, independent of the session check.
Detect
  • • Alert on logins succeeding from a device and geography never seen for that account.
  • • Alert on the same session id presented from two distinct network locations within a short window.
  • • Alert on a spike in failed logins per source and per account, distinguishing stuffing from targeted attempts.
Respond & recover
  • • Revoke the session server-side; a cookie you cannot revoke is a design decision you are now paying for.
  • • Force credential re-establishment and check for persistence created during the window.
  • • Notify through a channel the attacker did not just change.
Residual risk
  • • A phished credential presented by the real user through the real form is indistinguishable from a legitimate login without device or behavioural signals.
  • • Malware on the user's device defeats every server-side control by acting inside the authenticated session.
  • • Session lifetime is a permanent trade between the cost of re-authentication and the value of a stolen token.

Misconceptions

Claim
“HTTPS means the login is secure.”
Reality
TLS protects one hop. It does nothing about how the password is stored, how the session id is generated, whether the cookie is readable by scripts, or whether the next request is authorized.
Claim
“Hashing the password in the browser adds security.”
Reality
It makes the hash the password — an attacker who captures it can replay it. Client-side hashing is only meaningful as an addition to server-side hashing, never as a replacement.