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.
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.