Chapter Five · Identity — Who Is Calling

Identity — Who Is Calling

The security review of Stagedoor found passwords hashed with unsalted SHA-256, a JWT library that accepted alg: none, a session that could not be revoked, a "Sign in with Google" flow that trusted the email claim without checking who issued the token, one scanner key shared by every organizer in the country, and an order endpoint that checked whether the order existed but not whose it was. Seven topics rebuild identity from the password up: who the caller is, then what they may do, then which tenant's data they may touch.

7 topics

Chapter 4 built the auth ring and left it empty: a ring that "verifies the token and fills the principal into the context," with the token, the verification and the principal all deferred to here. This chapter fills it. The password is hashed with argon2id at a cost of 100 milliseconds, behind a rate limiter that refuses the 11th attempt, with one error for both failures and a constant-time path so the timing reveals nothing. The browser gets a session in Redis that a single delete can end; the mobile app gets a 15-minute access token and a 30-day refresh token that is a session under another name. The JWT verifier pins its algorithm and makes five checks on every token, explicitly. The Google login exchanges its code server to server, verifies the id token's audience and issuer, links by issuer and subject, and then issues Stagedoor's own session. The scanner gets one key per organizer, hashed at rest, carried in a header, rotated with an overlap.

Then the second question. Authorization is a domain rule that needs the caller and the resource, so it lives in the domain operation that does the work, shared by the API and the worker, with the owner in the query so the load without the check cannot be written; the order endpoint's year-long insecure direct object reference closes there, and the 404-or-403 table that Chapter 3 promised is written down. The last topic draws the tenant boundary three times, in the context, in the repository and in a row-level security policy that turns a forgotten WHERE into an empty result instead of every organizer's data.

None of the three wounds from Chapter 1 closes in this chapter; seat 14C, the double charge and the late emails wait for Chapters 6 through 8. What closes is the list from the security review, all six items, and the boundary that Chapter 3 drew and Chapter 4 gave an inside now has a door with a lock that reads the current role, not the one frozen in a token an hour ago.

Three questions in order: who is calling, what may they do, whose data may they touch
Passwordverified, never read
Session or tokenby client
JWTfive checks, every time
Providervouches at the door
Machineone key per client
May theydo this to that
Whose rowsthe tenant, three times

Topics in This Chapter

Topic 24
Passwords, Properly
Why a fast hash is wrong even with a salt, and what argon2id's 64 MiB defends against. The login endpoint that reveals nothing in its message or its timing, and the table that upgrades itself one login at a time.
Identity
Topic 25
Sessions vs Tokens
A row the server can delete against a statement the client carries. Which of Stagedoor's clients gets which, why revocation is the whole difference, and why the refresh token is a session by another name.
Identity
Topic 26
JWT Anatomy and Its Traps
Three base64 parts and the five checks a verifier must make on every one. The alg: none and algorithm-confusion forgeries and the one rule that stops both, key rotation with kid, and the short list of places a JWT belongs.
Identity
Topic 27
OAuth 2.0 and OIDC as a Client
The authorization-code flow with PKCE and state, exchanged server to server so no token touches the browser. What the id token proves, why accounts link by issuer and subject rather than email, and why Stagedoor issues its own session afterwards.
Identity
Topic 28
API Keys and Service-to-Service Auth
The scanner's key done properly: 256 bits with a prefix, hashed at rest, one per organizer, scoped, rotated with an overlap. Short-lived tokens and workload identity between Stagedoor's own services, and mutual TLS in one paragraph.
Identity
Topic 29
Authorization — Ownership and Roles
The order endpoint that checked existence and not ownership for a year, and the structural fix that makes the owner part of the query. Four roles, one permission table, deny by default, and the role read at check time rather than from a token.
Identity
Topic 30
Multi-Tenancy in One Codebase
340 organizers in one database, invisible to each other. The tenant on every row, in the context, required by every repository function, and enforced by row-level security so a forgotten clause returns nothing. The cross-tenant operations, named, and the three layouts.
Identity