The Core Difference
- 401 Unauthorized — "I don't know who you are." The request lacks valid authentication credentials. The client should authenticate and retry.
- 403 Forbidden — "I know who you are, but you can't do this." The server understood the request but refuses to authorize it. Re-authenticating won't help.
When to Use 401
Return 401 when:
- No authentication token/credentials were provided
- The provided token has expired
- The credentials are invalid (wrong password)
- The API key is missing or malformed
Important: 401 responses MUST include a WWW-Authenticate header that indicates the authentication scheme (Basic, Bearer, etc.).
When to Use 403
Return 403 when:
- User is authenticated but lacks the required role/permission
- IP-based access control blocks the request
- The resource exists but the user is not allowed to access it
- CSRF token validation fails
The Decision Tree
- Are credentials provided? → No → 401
- Are credentials valid? → No → 401
- Does user have permission? → No → 403
- Everything OK → 200
Common Mistake: Using 404 Instead of 403
Some APIs return 404 instead of 403 for resources the user can't access. This is a security practice (information hiding) — it prevents attackers from discovering which resources exist. GitHub does this for private repositories.