On this page
- Authentication vs authorization: The distinction that causes the bugs
- Choosing and designing: The decisions behind the login flow
- Authorization: Every object needs an owner check
- Login mechanics: Sessions, cookies, and tokens
- Credentials: Passwords, hashing, and the alternatives
- Federated login: OAuth and third-party identity
- Session hygiene: Headers, policies, and expiry
- Abuse controls: Rate limiting and account protection
- Testing auth: Proving the checks exist
- Common mistakes: The twelve that keep showing up
- Checklist
- FAQ
- Related topics
- Sources
Authentication and Authorization for AI Builders: Who You Are, and What You're Allowed to Touch
Login, sessions, JWTs, OAuth, passkeys, and the object-level checks your AI assistant skips. Every auth concept a vibecoder needs, with a linked guide for each.
Quick answer
- Authentication answers “who is this?” Authorization answers “what may they touch?” AI assistants implement the first and skip the second.
- Broken access control is the most common serious flaw in AI-generated CRUD apps: the code checks login, not ownership.
- How you store passwords, how long sessions last, and how tokens are revoked are decisions the assistant will make for you if you don’t.
- JWTs are not automatically more secure than sessions. Revocation is the tradeoff, and most small apps don’t need it.
- Test auth by trying to read someone else’s record with your own valid session — that’s the check that finds the real bug.
- Every concept below links to a full guide. Start with access control, then login mechanics.
Authentication vs authorization: The distinction that causes the bugs
Authentication is proving identity: a password, a passkey, a token from a provider. Authorization is deciding what that identity may do. They’re implemented in different places and fail differently — an authentication bug locks people out, while an authorization bug quietly hands one user another user’s data.
AI assistants are reliably good at the first and unreliable at the second. Registration, login, password reset, and session handling are well-trodden patterns with obvious shapes to generate. Authorization is contextual: it depends on who owns what, which records are private, which roles exist, and which fields are meant to be visible. None of that is inferable from a prompt that says “add a dashboard.”
So the guides below start with authorization even though authentication comes first in the flow, because authorization is where generated apps actually break.
Choosing and designing: The decisions behind the login flow
Before any of the mechanics, three decisions set the shape of everything else: how users prove who they are, which method you accept, and what your permission model allows. They’re the expensive ones to change after you have users, and the ones generated code makes silently by default.
- How to Choose an Authentication Method for Your App: A Decision Guide — Sessions, JWTs, OAuth, passkeys, magic links, and SSO compared, with the six questions that decide it.
- What Are the Different Types of Authentication (and What Is Each One For)? — The three factors and the eight method families built on them, with what each is for and where it’s weak.
- How to Design Authorization for Your App (So Users Can’t Reach Each Other’s Data) — Ownership, roles, tenants, and admin access, designed so the check lives in the query.
Authorization: Every object needs an owner check
The canonical failure is an endpoint like GET /invoices/42 that verifies a session and then fetches invoice 42. Any logged-in user can read any invoice by changing the number. This is broken access control, also called IDOR (insecure direct object reference), and it survives review because the code contains a real, working permission check — just the wrong one.
- What Is Broken Access Control (IDOR)? — The flaw class, why it’s the top of the OWASP list, and how it presents.
- How to Test Your App for Broken Access Control — The manual check: use your own session to request someone else’s object.
- What Is Zero Trust Architecture? — Verify each request on its own merits instead of trusting a prior login.
- What Is a Non-Human Identity (NHI)? — The other side of the model: services and agents that also need scoped rights.
Login mechanics: Sessions, cookies, and tokens
Once a user proves who they are, something has to carry that proof across requests. That carrier is a session cookie, a token, or a signed assertion, and each has different properties around expiry, revocation, and exposure. The assistant picks one, usually the one most represented in its training data, which is not the same as the one that fits your app.
- JWT Security: Common Mistakes That Get Tokens Stolen — Algorithm confusion, missing expiry, tokens in local storage, and unverified signatures.
- What Is CSRF (Cross-Site Request Forgery)? — Why cookie-based sessions need protection that token-based auth doesn’t.
- What Is HSTS (and Why Your HTTPS Isn’t Enough)? — Making browsers refuse to send credentials over plain HTTP.
- What Is a Man-in-the-Middle Attack? — What an attacker gains when the connection isn’t verified.
Credentials: Passwords, hashing, and the alternatives
Password handling is the one place where a mistake is unrecoverable rather than merely exploitable: if you store passwords in a form that can be reversed, a database leak becomes a credential leak for every user, including on other sites. Hashing with a per-user salt and a slow algorithm is the baseline, and it’s a decision the assistant makes for you in one line.
- How to Store Passwords Correctly (Hashing vs Encryption) — Why encryption is the wrong tool and which hashing algorithm to use.
- What Are Passkeys (and Should You Switch)? — Phishing-resistant credentials bound to a device.
- What Is Phishing-Resistant MFA? — Which second factors actually resist an attacker, and which don’t.
- What Is Credential Stuffing (and How Does It Get Your Accounts)? — Why passwords leaked elsewhere become your problem.
- How to Prevent Credential Stuffing Attacks — Rate limiting, breach checks, and detecting the pattern.
Federated login: OAuth and third-party identity
“Sign in with Google” is an OAuth flow, and the gap between a working integration and a correct one is mostly verification: confirming the token was issued for your client, checking the audience, and deciding what to do about an email that already exists in your database. Assistants wire up the happy path and leave the identity-linking edge cases for you to discover.
- What Is OAuth 2.0? — Authorization code flow, scopes, and where the trust lives.
- What Is Open Redirect (and Why Do Phishers Love It)? — The related flaw in redirect handling that auth flows introduce.
- Why Your Frontend API Keys Are Not Secret — Which credentials belong in a browser-visible client and which never do.
Session hygiene: Headers, policies, and expiry
A login is only as safe as the transport and the surrounding browser policy. Security headers do more work than most builders expect: they prevent content injection, restrict where a page can submit credentials, and force HTTPS. None of them are part of the feature the assistant was asked to build, which is why they’re usually absent.
- What Are Security Headers (and How Do You Add Them)? — The set worth adding, in order.
- What Is Content Security Policy (CSP)? — Limiting which scripts may run, which blunts stolen-session attacks.
- What Is Clickjacking (and How Do You Prevent It)? — Why
X-Frame-Optionsbelongs on logged-in pages. - How to Manage Secrets and Environment Variables Properly — Keeping signing keys out of the repository.
Abuse controls: Rate limiting and account protection
Authentication endpoints are the ones attackers point bots at, because unlimited attempts make every other control moot. Rate limiting per IP and per account, plus a lockout or slowdown policy, is the difference between an unusable attack and thousands of successful ones.
- What Is Rate Limiting? — The concept and where to apply it.
- How to Add Rate Limiting to an API — Implementation, including per-account limits on login.
- Why Does My App Ignore SIGTERM (and How Do I Fix It)? — Why sessions in memory vanish when a deploy restarts the process.
Testing auth: Proving the checks exist
You can’t tell whether authorization works by reading one endpoint — the bug is always on the endpoint someone forgot. The practical approach is a short, repeated test: log in as user A, request user B’s resources by ID, and confirm a 403 or 404 for every one of them. Do it per feature, not once at the end.
- How to Test Your App for Broken Access Control — A manual method that works without security tooling.
- What Is Penetration Testing (and Do You Need One)? — When to bring in someone outside the team.
- How to Add SAST Scanning to a GitHub Repo — Automated scanning that catches some of these classes on every commit.
- What Is the OWASP Top 10? — The reference list broken access control sits at the top of.
Common mistakes: The twelve that keep showing up
Most auth failures in generated apps come from a short list of recurring defects — reversible password storage, tokens decoded but never verified, logout that doesn’t invalidate, reset links that never expire, MFA enforced in the UI rather than the session, and endpoints that authenticate without authorizing. They’re worth reading as a set, because each one passes a demo and a code review.
- The 12 Authentication Mistakes That Show Up in AI-Generated Apps — Each defect with the failure it causes, why generated code produces it, and the fix.
Where this bites vibecoders
The prompt was “add a projects page where users can see their projects,” and the assistant delivered exactly that — for the user who asked. The route checks the session, the query fetches by project ID, and the UI only ever links to the signed-in user’s projects, so clicking around the app confirms it works. What the code never encodes is the rule that a project belongs to a person: no ownership condition in the query, no role check on the update endpoint, no restriction on which fields a user may set. Every one of those is invisible in normal use and trivially exploitable by anyone who edits an ID in the URL, which is precisely the class of flaw scanners report as broken access control. When you accept auth code from an assistant, verify the negative case — what happens when a valid user requests something that isn’t theirs — because that’s the only case the generated code tends not to handle.
Checklist
- Check ownership in the query, not just the route: fetch where ID and user match.
- Test every user-specific endpoint with a second account before shipping the feature.
- Hash passwords with a slow, salted algorithm — never store them reversibly.
- Set session expiry, and make logout actually invalidate the session.
- Put rate limits and lockouts on login, registration, and password reset.
- Verify OAuth tokens were issued to your client before trusting them.
- Add security headers to every response, especially on authenticated pages.
- Never put signing keys or service credentials in front-end code.
- Re-run the access-control test whenever a new endpoint is added.
FAQ
Why can users see each other’s data in the app my AI built?
Because the endpoint checks whether you’re logged in but not whether the record belongs to you. The assistant implements authentication (is there a valid session?) and skips authorization (does this user own record 42?). The fix is an ownership check on every query for a user-specific record, not just on the route.
Should I use sessions or JWTs?
Use server-side sessions for a normal web app with a browser front end — logout, revocation, and expiry are straightforward. Reach for JWTs when you have multiple services that need to verify a caller without a shared session store, and accept that revocation becomes your problem. Most small apps that adopt JWTs by default would be simpler with sessions.
Is OAuth the right way to add ‘Sign in with Google’?
Yes for the sign-in flow itself — it’s the standard. The mistake is treating the provider’s job as done once you receive the token. You still need to create or link a local account, decide what happens when the email changes, and check that the token was issued to your application and not to someone else’s.
Where should the authorization check live?
In the data access layer, next to the query, so the ownership condition is part of the fetch: select the record where the ID and the user match. Putting checks in the route handler or the UI means every new endpoint has to remember to call them, and the one that forgets is the vulnerability.
Related topics
- What Is Broken Access Control (IDOR)?
- JWT Security: Common Mistakes That Get Tokens Stolen
- What Is OAuth 2.0?
- How to Store Passwords Correctly (Hashing vs Encryption)
- How to Test Your App for Broken Access Control
- What Is Phishing-Resistant MFA?
- What Is CSRF (Cross-Site Request Forgery)?
- What Are Passkeys (and Should You Switch)?
- InfoSec for Vibecoders