Authentication vs Authorization
Authentication and authorization are two different questions. Authentication (authN) asks who are you? Authorization (authZ) asks what are you allowed to do? They always happen in that order — you can't determine permissions for a user you haven't identified yet. Confusing the two is how security bugs happen.
Authentication vs Authorization
Authentication (AuthN)
Request + Credentials
username / password
AuthN Verification
validate identity
Identity Established
user = alice
AuthN Factors
Know: password
Have: phone / key
Are: biometric
Authorization (AuthZ)
Resource A
/api/orders/123 (alice's)
Allowed
alice owns order 123
Resource B
/api/admin/users
Denied
alice is not admin
AuthZ Models
RBAC: role-based
ABAC: attribute-based
ReBAC: relationship-based
IDOR Vulnerability (Insecure Direct Object Reference)
AuthN Passes
attacker is authenticated
Change ID
/api/orders/123 → /api/orders/124
No AuthZ Check
server returns order 124 data
AuthN Passes
attacker is authenticated
Change ID
/api/orders/123 → /api/orders/124
AuthZ Check Present
attacker != owner → 403 Forbidden
AuthZ prevents IDOR
AuthN passing does not mean AuthZ passing — always check both
Authentication — Proving Identity
Authentication is the process of verifying that someone is who they claim to be. When you type your password into a login form, the system checks it against a stored hash. If it matches, you've authenticated. The system now knows (with some confidence) that you're the account holder.
Authentication factors fall into three categories:
- Something you know: passwords, PINs, security questions.
- Something you have: a phone (for SMS or TOTP codes), a hardware security key (YubiKey), a smart card.
- Something you are: fingerprints, face recognition, retina scans.
Multi-factor authentication (MFA) combines two or more of these categories. A password plus a TOTP code from an authenticator app uses "know" and "have." This matters because compromising two different factor types requires two different attack vectors.
Not all factors are equal. SMS-based MFA is the weakest second factor because phone numbers can be hijacked via SIM swapping — an attacker convinces your carrier to transfer your number to their SIM card. It's still better than no MFA at all, but hardware keys and authenticator apps are meaningfully more secure.
Authorization — Determining Permissions
Once the system knows who you are, it needs to decide what you're allowed to do. This is authorization. You might be authenticated as a valid user but not authorized to access the admin panel, delete other users' data, or read a specific document.
There are several models for making authorization decisions:
RBAC (Role-Based Access Control) assigns permissions to roles, then assigns roles to users. A user with the "editor" role can edit posts; a user with the "admin" role can do everything. RBAC is simple and works well when your permission model maps cleanly to job functions. Most applications start here.
ABAC (Attribute-Based Access Control) makes decisions based on attributes of the user, the resource, and the context. "Allow access if the user's department is engineering AND the resource is classified as internal AND the request comes from the corporate network." ABAC is more flexible than RBAC but harder to reason about and audit.
ReBAC (Relationship-Based Access Control) determines access based on the relationship between the user and the resource. Google Docs is the canonical example: you can view a document because someone shared it with you, or because it's in a folder you have access to, or because it's public. ReBAC models permission as a graph, which is powerful but complex to implement. Google's Zanzibar paper formalized this approach.
The Principle of Least Privilege
Regardless of which model you use, the guiding principle is the same: give users and services the minimum permissions they need to do their job, and nothing more. This limits the blast radius when (not if) credentials are compromised.
In practice, this means your API service account doesn't get admin access to the database. Your frontend deploy pipeline doesn't get permission to modify IAM policies. Your intern's AWS account doesn't have *:* on all resources. Every extra permission is an extra thing that can go wrong.
The Confused Deputy Problem
A confused deputy is a program that gets tricked into misusing its authority. Imagine a service that has permission to read any user's files. A malicious user sends it a request that causes it to read another user's files and return the contents. The service (the deputy) has the authority — it just used it on behalf of the wrong party.
This is why authorization checks need to happen at the right layer. The service needs to verify not just "do I have permission to read this file?" but "does the requesting user have permission to read this file?"
Where Authorization Breaks
Most API security breaches aren't caused by broken authentication. They're caused by broken authorization. Here are the patterns that keep showing up:
Checking on the client only. Your frontend hides the "Delete" button for non-admins. An attacker opens DevTools and sends the DELETE request directly. The server never checked permissions because the frontend was "handling it."
Checking at the wrong layer. Your API gateway validates the JWT and confirms the user is authenticated. But the downstream service that actually fetches the data never checks whether this specific user is authorized to access this specific resource. Authentication passed, authorization was never performed.
IDOR (Insecure Direct Object Reference). Your API exposes /api/orders/123. A user changes the URL to /api/orders/124 and gets someone else's order. The server verified the user was logged in but never checked if they owned order 124. This is the most common authorization vulnerability in web applications, and it's embarrassingly simple to exploit.
# This is an IDOR vulnerability — the server trusts the ID from the URL
GET /api/orders/124
Authorization: Bearer <valid-token-for-user-A>
# Response: order belonging to user B
{ "id": 124, "user": "user-b", "total": 89.99 }
The fix is straightforward: every data access query should be scoped to the authenticated user. Instead of SELECT * FROM orders WHERE id = 124, it should be SELECT * FROM orders WHERE id = 124 AND user_id = <authenticated_user_id>.
Real-World Impact
The 2019 First American Financial data exposure leaked 885 million records — social security numbers, bank account details, mortgage documents — through a simple IDOR vulnerability. The authentication was fine. The authorization was missing entirely. Anyone who could guess (or increment) a document ID could access any document in the system.
This is the pattern across the industry. OWASP's API Security Top 10 lists Broken Object Level Authorization (their name for IDOR) as the number one API security risk. Not because authentication is easy and authorization is hard — both are hard — but because teams invest heavily in authentication (SSO, MFA, OAuth flows) and then forget that every endpoint also needs to answer the question: is this specific user allowed to access this specific resource?
Key Takeaways
- Authentication (who are you?) always comes before authorization (what may you do?). They are separate concerns that require separate checks.
- MFA significantly reduces account compromise risk, but not all factors are equal — hardware keys beat SMS.
- RBAC, ABAC, and ReBAC are authorization models with different complexity and flexibility tradeoffs; most apps start with RBAC.
- The principle of least privilege limits blast radius: grant only the permissions necessary for the task.
- IDOR is the most common authorization vulnerability — always scope data queries to the authenticated user.
- The majority of API breaches stem from broken authorization, not broken authentication.
Next up: Hashing and Encryption — the most-confused pair in security, and why the difference matters for every system you build.
Enjoyed this breakdown?
Get new lessons in your inbox.