Authentication answers 'Who are you?' (proving your identity with a password, fingerprint, or token). Authorization answers 'What are you allowed to do?' (can you read this file, edit that post, delete this user?). Both are necessary; neither replaces the other.
5 min read
Many people use "authentication" and "authorization" interchangeably. They're not the same:
A concrete example: you walk into a bank with an ID. The teller checks your ID to verify you are Alice Smith (authentication). Then they check a list: "Alice Smith has permission to withdraw from Savings Account #1234 but not to access the vault" (authorization).
Authentication is the first step. You must prove who you are. Common methods:
The point of authentication is to answer: Is this actually the person they claim to be?
In web applications, authentication typically starts with a login form:
<form>
<input type="email" name="email" />
<input type="password" name="password" />
<button type="submit">Sign In</button>
</form>Your backend receives the email and password, looks them up, verifies the password is correct (by hashing, covered in the next lesson), and if so, issues a credential — usually a session token or JWT — that proves the user is authenticated.
Once you've proven who you are, authorization decides what you can do. Common patterns:
1. Role-Based Access Control (RBAC) — users have roles, roles have permissions:
User: alice
Role: Editor
Permissions: read:post, write:post, delete:own_post
Is alice allowed to delete this post? Check: is the post owned by alice? If yes, does editor role have delete:own_post? If both yes, allow. Otherwise deny.
2. Attribute-Based Access Control (ABAC) — decisions based on attributes of user, resource, and environment:
Rule: allow if (user.department == "sales" AND resource.type == "report" AND resource.label == "public")
3. Direct permissions — each user has a list of specific things they can do:
alice:
- view: document #1234
- edit: document #1234
- delete: document #1234
bob:
- view: document #1234
The point of authorization is to answer: Given that we've verified this is alice, should alice be allowed to perform this action?
Notice: steps 2-3 are authentication. Steps 8-9 are authorization. Both are required. You can't just check if someone has permission (what if they're not who they claim to be?). You can't just verify someone's identity (what if they're not allowed to do this specific action?).
Confusing identity with authorization
# WRONG — just checking if user is logged in
if request.user:
return allowed_to_perform_action() # assumes logged-in = permission grantedCORRECT — checking both
if not request.user:
return 401 # not authenticated
if not user_has_permission(request.user, 'edit_post', post_id):
return 403 # authenticated but not authorizedStoring passwords in plain text
Never do this. Even if your infrastructure is perfect, a data breach exposes plaintext passwords for every user. Hash passwords so that even you (the developer) can't read them. Covered in the next lesson.
Trusting the client to enforce authorization
// WRONG — frontend decides if button is shown
if (user.role === 'admin') {
showDeleteButton(); // shows button only for admins
}The frontend is untrusted — a user can open DevTools and make the button appear, or send a DELETE request directly. Authorization must be enforced on the backend, where a malicious user can't bypass it.
# CORRECT — backend enforces authorization
@app.delete('/posts/<post_id>')
def delete_post(post_id):
if not user_has_permission(request.user, 'delete_post', post_id):
abort(403) # backend says no, regardless of what client sent
delete_post_from_database(post_id)In a multi-tenant system (one application serves many organizations), authorization becomes critical. Alice from Company A should never see Bob's data from Company B, even if Bob forgot to set privacy flags.
Authorization rule in a multi-tenant app:
def can_view_document(user, document_id):
document = fetch_document(document_id)
# Step 1: is this user authenticated?
if not user:
return False
# Step 2: does this document belong to the user's organization?
if document.organization_id != user.organization_id:
return False
# Step 3: does the user have permission within their organization?
if not user.has_permission('view_document'):
return False
return TrueThe second check (organization membership) is critical. If you skip it, a user from Company A can view Company B's documents just by knowing the ID. This is a classic multi-tenant data leak.
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. What is the primary purpose of authentication?
2. Why must authorization be enforced on the backend, not just the frontend?
3. What is a multi-tenant data leak?
4. Which step comes first in a complete authentication + authorization flow?
Auth, Authorization & Multi-Tenancy