Authentication and authorization are related, but they answer different questions.
Authentication asks who the caller is. Authorization asks what that caller is allowed to do.
Quick answer
Authentication verifies identity. Authorization verifies permission.
If a user signs in with a password, session cookie, OAuth provider, or access token, the system is performing authentication. If the backend checks whether that user can view an invoice, update an account, delete a project, or call an admin endpoint, the system is performing authorization.
A secure backend needs both. Knowing who a user is does not automatically mean the user can perform every action.
Authentication answers who you are
Authentication creates or confirms an identity for the current request.
Common authentication mechanisms include:
- Username and password login.
- Server-side session cookies.
- JWT access tokens.
- OAuth or OpenID Connect login.
- API keys for service or integration access.
- Client certificates in stricter service environments.
After authentication succeeds, the backend usually has a principal: a user ID, service ID, client ID, or account context.
For example:
request -> session_id -> user_id = 42
request -> bearer token -> subject = user_42
request -> api key -> integration = billing-exporter
That identity is only the starting point.
Authorization answers what you can do
Authorization checks whether the authenticated caller can perform a specific action on a specific resource.
Examples:
- Can user 42 read invoice 9001?
- Can this support agent reset a customer’s password?
- Can this API client write to the
paymentsscope? - Can this service publish events for this tenant?
- Can this user delete a project they do not own?
Authorization often depends on roles, permissions, scopes, ownership, tenant membership, account status, feature flags, and business rules.
This check should happen on the server. Frontend checks can hide buttons and improve usability, but they are not security controls.
A practical example
Imagine a project management API:
DELETE /api/projects/proj_123
Authorization: Bearer eyJhbGciOi...
Authentication validates the bearer token and identifies the caller:
subject = user_42
tenant = acme
Authorization then checks the action:
Can user_42 delete proj_123 in tenant acme?
The answer might depend on whether the user owns the project, has an admin role, belongs to the tenant, and whether the project is locked.
If the backend only verifies the token and skips the permission check, any signed-in user might delete resources they do not own.
Roles, permissions, and scopes
Authorization models can be simple or complex.
Roles group permissions:
admin -> users:read, users:write, billing:read
viewer -> users:read
Permissions describe allowed actions. Scopes are often used in OAuth access tokens to describe what a client or token can request.
Roles are easy to understand, but they can become too broad. Permissions are more precise, but they require careful management. Scopes are useful at API boundaries, but they do not replace object-level checks.
For example, a token with invoices:read may be allowed to call invoice endpoints, but the backend still needs to check which invoices the user can actually read.
401 vs 403
Authentication and authorization also affect HTTP response codes.
Use 401 Unauthorized when authentication is missing, invalid, or expired. Despite the name, 401 is usually about authentication.
Use 403 Forbidden when the caller is authenticated but not allowed to perform the action.
Example:
{
"error": "forbidden",
"message": "You do not have permission to delete this project."
}
Read REST API Status Codes Explained for the broader status code model and REST API Error Handling Best Practices for stable error response design.
Common mistakes
The first mistake is checking authentication but not authorization. A valid user session does not prove the user owns the target resource.
The second mistake is trusting user IDs, roles, or tenant IDs from request bodies. The backend should derive trusted identity from the session, token, or verified credential.
The third mistake is relying on frontend route guards. Attackers can call APIs directly.
The fourth mistake is using one broad admin flag for everything. Admin permissions often need boundaries, audit logs, and stronger checks for sensitive actions.
The fifth mistake is putting too much authorization state into long-lived JWTs. If roles or permissions change, old token claims may stay stale until expiration.
Practical backend recommendation
Keep authentication and authorization separate in your design:
- Authenticate the caller early.
- Build a trusted request context from the verified session or token.
- Check authorization close to the action and resource.
- Return clear
401and403responses. - Log authorization denials without leaking sensitive data.
- Test object ownership and tenant boundaries explicitly.
When in doubt, ask two questions for every protected endpoint: who is calling, and can that caller do this specific thing to this specific resource?
Related reading
Read JWT vs Session Authentication for login architecture tradeoffs, API Authentication Best Practices for protected API checks, and OAuth Scopes Explained for token permission labels. For access control models, read RBAC vs ABAC and Least Privilege Explained. For token contents, read JWT Claims Explained. For the full sequence, browse the Authentication Learning Path.
For the broader security sequence, browse the Backend Security Learning Path.