HTTP 401 vs. 403 β Definition and Differences
Compare the two access-denied statuses: which means unauthenticated, which means forbidden, and how to diagnose each quickly.
Both refuse a request, and they say different things. 401 means the server does not know who you are; 403 means it knows and refuses anyway.
1. The Distinction
| 401 Unauthorized | 403 Forbidden | |
|---|---|---|
| Actually means | Not authenticated | Authenticated but not permitted |
| Credentials | Missing, malformed, or expired | Valid |
| Challenge header | WWW-Authenticate expected |
None |
| Would new credentials help? | Yes | No |
| Fix | Supply a valid credential | Change permissions, or stop |
The name of 401 is a historical misnomer: it is about authentication despite being called "Unauthorized".
2. Diagnosing a 401
Check, in order:
- Was a credential sent at all? Header names differ per API.
- Is it correctly formed β the right prefix, no stray whitespace, not truncated?
- Has it expired, and did the refresh path actually run?
- Is it the right environment's credential?
- Is the system clock correct, for signed tokens?
Read the WWW-Authenticate header; well-built APIs put the specific reason there.
3. Diagnosing a 403
A 403 means identity was established, so the credential is not the problem. Check:
- Does this identity have the required role or permission?
- Does the token carry the necessary scope? A read-only token gets
403on a write. - Is this resource owned by someone else?
- Is a policy blocking by address, country, or path rather than by user?
- Is a rate or abuse rule producing it?
4. Where 403 Gets Used Loosely
Some servers return 403 for conditions that are not permission decisions:
- Bot rules refusing automated traffic.
- Geographic restrictions.
- A firewall matching a request pattern.
- Hotlink protection based on the referrer.
In those cases nothing about the user's permissions is at issue, which is why the error page usually explains more than the status does.
5. For Automated Clients
Treat them differently in code. A 401 is worth one re-attempt after refreshing the credential; a 403 should not be re-attempted at all, because nothing about repeating the request will change the outcome.
Retrying a 403 in a loop is a common way to convert a refusal into a longer-lasting block.
6. For API Designers
Return 401 only when authentication failed, 403 only when an authenticated caller lacks permission, and include a machine-readable reason in the body.
Some APIs deliberately return 404 instead of 403 so that resource existence is not revealed to unauthorised callers. That is a legitimate choice, and worth documenting so consumers are not chasing a missing resource that is really a permission problem.
7. Quick Triage
- Credential absent or clearly wrong β expect
401. - Credential works elsewhere but not here β expect
403. - Whole site refuses from one network β a policy
403. - Works in a browser, fails from a script β a client-classification
403.
8. Summary
401 is an authentication failure and is fixed by supplying valid credentials; 403 is an authorisation or policy refusal and is not.
The practical rule for clients: refresh and re-attempt once on 401, and never loop on 403 β read what the response body says instead.