Authentication vs Authorization: Who You Are vs What You May Do
Authentication vs authorization explained: who you are versus what you may do, and why data in vibe-coded apps usually leaks through the second one.
Authentication is checking who you are: the app makes sure a person really owns the account. Authorization is checking what you may do: whether this person can read this order, edit this profile, open this admin page.
The words look alike and get mixed up constantly. But authentication vs authorization is a real distinction: they are two separate checks, and they break in different ways. Especially in apps built with AI.
Authentication vs authorization, hotel edition
At the front desk they ask for your passport. That is authentication: the hotel confirms you are the person the room was booked for. Then they hand you a key card. It opens your room, the lift and the gym, but not other guests’ rooms or staff areas. That is authorization.
The key point is that the second check happens at every door, not once at the entrance. The lock on room 512 does not care that you showed a passport at reception. It checks whether your card has the right to open room 512.
Apps work the same way:
- Authentication is logging in with a password, an email code or Google. The result is a session: the app knows requests are coming from the user with ID
user_17. - Authorization is a check on every request: may
user_17fetch invoice 9381? Delete this comment? Change their own pricing plan?
You can see the difference in server errors too: 401 Unauthorized usually means “I don’t know who you are”, while 403 Forbidden means “I know who you are, and you can’t come in here”.
Why leaks usually come from authorization
Hardly anyone writes authentication from scratch these days. It comes ready-made: Supabase Auth, Firebase, Clerk, Auth0 and the like. These services have spent years getting login, password reset and session handling right, and AI assistants wire them up fairly well. Login works, and many people stop there.
Authorization never comes ready-made. The rules of who can do what are different for every product: who sees an order, whether a manager can edit someone else’s deals, what the free plan allows. You have to spell them out yourself, and that is exactly where AI tends to cut corners.
A typical picture in a vibe-coded app:
- Checks only in the interface. There is no “open someone else’s invoice” button, but a request to
/api/invoices/9381returns any invoice to any logged-in user. The server checked that you are logged in, not that the invoice is yours. - The role is stored with the user. An
isAdminflag sits in a profile the user can edit, or simply arrives from the browser. - Access by ID. Record IDs are sequential, so counting through them downloads the whole database. This is called IDOR, an insecure direct object reference.
- Open tables. In Supabase, a table without access rules returns every row to anyone holding the public key, and every visitor to your site holds it.
In all these cases, login works perfectly. An attacker does not need to hack anything: they sign up like anyone else and politely ask for other people’s data.
How to get authorization right
- Check on the server, on every request. The interface can hide buttons for convenience, but the backend or database access rules make the actual decision.
- Take the owner from the session, not the request. The server already knows who is logged in. If
user_idarrives in the request body and the server trusts it, anyone can swap in someone else’s. - Look records up together with their owner. Not “find invoice 9381” but “find invoice 9381 belonging to this user”. Someone else’s invoice then simply is not found.
- Keep roles where users cannot reach them. A separate table or a field only the server can change.
- Deny by default. A new table or endpoint stays closed until you explicitly decide who gets in.
How to check your own app
Create two ordinary accounts. With the first, create something private: an order, a document, a message. Copy its ID from the address bar or the Network tab. Log in as the second user and request that record directly: read it, edit it, delete it. Then try opening the admin pages as a regular user.
If any of those requests succeeds, the problem is not login. It is authorization, and that is what needs fixing.
In short
- Authentication answers “who are you”; authorization answers “what may you do”.
- Authentication is usually off the shelf and works; authorization is custom for every app, and that is where the holes are.
- A hidden button is not protection: permission checks belong on the server, on every request.
- The owner of a record comes from the session, not from data the browser sent.
- The simplest test is two accounts and one trying to reach the other’s data.
SUBXCAT reviews authorization in AI-built apps and closes the gaps before your users find them.