Playbook
Authentication is the one part of your app where an AI's confident shortcut isn't a bug — it's a breach. Everywhere else, a hallucinated function fails loudly and you fix it. In auth, a plausible-looking mistake can ship silently and stay invisible until someone logs into an account that isn't theirs, or dumps your user table. The stakes are categorically different, so the rules are categorically stricter: you review every line, you trust nothing, and you never hand-roll what a battle-tested library already does right. Auth is the wrong place to be clever and the wrong place to save time.
Step 1: Don't build it yourself — use a proven library or provider
The most important auth decision is to not write your own. Password hashing, session management, token handling, and the dozens of subtle attacks these defend against have been solved, audited, and hardened by people who do only this. Your job is to use that work, not reinvent it. So direct the agent to build on your framework's official auth system or a reputable auth provider — never to roll a custom login from scratch. The moment an agent starts writing its own password hashing or its own token scheme, stop it. Every custom auth primitive is a vulnerability you now own and probably can't spot. Boring, standard, well-worn auth is the secure choice, always.
Step 2: Get the password and session basics right
If you're handling passwords at all, a short list is non-negotiable, and you must confirm each one is actually true in the code the agent produced — not assume it:
- Passwords are hashed, never stored or logged in plain text. With a strong, slow, salted algorithm (bcrypt, argon2, scrypt) — the ones the library uses by default. Grep the code to be sure a password never lands in the database or a log file as readable text.
- Sessions and tokens are secure. Session cookies set HttpOnly and Secure; tokens signed and expiring. The library handles this if you let it — verify it's turned on.
- Login errors don't leak. "Invalid email or password" for both wrong-email and wrong-password, so an attacker can't discover which emails are registered.
- Rate limiting on login. So someone can't brute-force passwords at machine speed.
Step 3: Enforce permissions on the server, on every request
This is the vulnerability agents introduce most often, and it's a real breach when they do. Hiding a button in the UI is not access control. Every protected action and every piece of data has to be checked on the server, on every request: is this user logged in, and are they allowed to do this specific thing to this specific record? The classic hole is the missing ownership check — the app confirms you're logged in but not that the invoice you're requesting is yours, so changing an ID in the URL hands you someone else's data. Direct the agent explicitly to enforce authorization server-side on every endpoint, and then test it by trying to access another user's data on purpose. If you can, the check is missing.
The security review prompt
Auth code gets a dedicated review pass, ideally by an agent that didn't write it. Here's the prompt we use:
Review this authentication and authorization code as a security
reviewer. For EACH item, quote the specific line that satisfies
it, or flag it as MISSING:
1. Passwords hashed with a strong salted algorithm; never stored
or logged in plaintext.
2. Session cookies HttpOnly + Secure; tokens signed and expiring.
3. Login errors are generic (no "user not found" leak).
4. Rate limiting on login / password-reset endpoints.
5. Every protected route checks authentication AND authorization
(does THIS user own THIS record?) on the SERVER.
6. No secrets, keys, or tokens hardcoded in the source.
7. Password reset tokens are single-use and time-limited.
Do not reassure me. If something is missing or weak, say so
plainly and show where.
Step 4: Test the attacks, don't just test the happy path
"I can log in" proves almost nothing. The security of auth lives in the failure cases, so test those on purpose. Try to reach a protected page while logged out. Log in as user A and try to view or edit user B's data by changing an ID. Submit a wrong password many times fast and see if anything slows you down. Try a password reset link twice and confirm the second use fails. These are the tests that find real holes, and they're exactly the ones an agent won't run unless you make it. Passing the happy-path test is the baseline; surviving the attack tests is the actual bar.
Step 5: Keep secrets out of the code
Auth involves secrets — signing keys, provider credentials, database passwords — and they belong in environment variables or a secrets manager, never committed to the repo. Agents will sometimes paste a key inline "for now." Never let that ship. Scan the diff for anything that looks like a credential before it's committed, because a leaked signing key undoes all the careful work above. This one is easy to check and catastrophic to miss.
Why this one gets extra caution
Everywhere else in this playbook series we say "verify, don't trust." In auth, we mean it twice. The failure mode isn't a broken feature you'll notice and fix — it's a quiet hole that works fine in every demo and gets discovered by the wrong person. AI is genuinely useful here for wiring up a standard, well-supported auth flow quickly. It is not a substitute for you reading every line and trying to break it yourself. Draft with the agent; own the review.
Auth is the place to slow down, and the checklist above is the minimum bar. Because this is where hallucinated shortcuts do the most damage, keep the AI coding security checklist open beside it, and if user data flows into a database, pair it with writing SQL with AI without corrupting data so the storage layer is as careful as the login. When it's all built and reviewed, deploying with AI gets it live without a midnight scramble.