HTTP 401 means the request lacks valid authentication, while HTTP 403 means authentication may be valid but access is still denied. That single split should guide most API, website, and security decisions. A 401 asks the client to prove identity; a 403 says identity is known, but permission is not enough.
TLDR: A 401 Unauthorized response should be used when a user is not logged in, sends no token, or sends an expired or invalid token. A 403 Forbidden response should be used when the user is logged in but lacks the right role, plan, scope, or policy permission. For example, if 10,000 API calls fail in one week and 62% involve expired tokens, those should likely be 401 responses; if 18% come from basic-plan users trying to access admin reports, those should be 403 responses.
What HTTP 401 Really Means
HTTP Status Code 401 is labeled Unauthorized, but the name is a bit misleading. In plain language, it usually means unauthenticated. The server cannot accept the request because the client has not supplied valid proof of identity.
Common causes include:
- No login session exists.
- An API key is missing.
- A bearer token has expired.
- A token is malformed or signed incorrectly.
- Basic authentication credentials are wrong.
A proper 401 response often includes a WWW-Authenticate header. That header tells the client what authentication method is expected. For example, an API might respond with a bearer-token challenge so the client knows it must send a valid access token.
Example:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api", error="invalid_token"
In this case, the server is not saying the user has no rights forever. It is saying, “The request cannot be trusted yet.”
What HTTP 403 Really Means
HTTP 403 Forbidden means the server understood the request and recognized the client situation, but refuses to allow the action. Authentication may already be valid. The problem is authorization.
Typical 403 cases include:
- A viewer tries to open an admin-only dashboard.
- A user has a valid token but lacks the required OAuth scope.
- A paid feature is blocked for free-tier accounts.
- An employee account is active but not assigned to a department resource.
- An IP address, region, or organization policy blocks the request.
Here, asking the user to log in again will not help. That is where teams waste time. It drives developers crazy when a system returns 401 for every access problem, because clients keep refreshing tokens when the real issue is a missing permission.
401 vs 403: The Practical Rule
The clean rule is simple:
- Use 401 when authentication is missing, invalid, expired, or unusable.
- Use 403 when authentication is accepted but the action is not allowed.
A useful question is: “Would logging in again fix this?”
- If yes, the response is probably 401.
- If no, the response is probably 403.
For example, a mobile app calls /api/profile with an expired token. The server should return 401 so the app can refresh the token or send the user back to sign in. The same app then calls /api/admin/users with a valid token from a normal customer account. That should return 403 because the user is known but not allowed to access admin data.
Why the Difference Matters
Correct status codes are not just neat technical labels. They affect user experience, security, monitoring, and client behavior.
For users, a 401 can trigger a login screen. A 403 should show a message such as, “This account does not have access to that page.” Mixing them up creates annoying loops. A user may sign in three times and still get blocked. Honestly, that feels like the software is broken.
For APIs, client apps depend on accurate status codes. A 401 may trigger token refresh logic. A 403 may disable a button, show an upgrade prompt, or display a permission request. If both errors return the same status, the client has to guess.
For security teams, the split helps detect different problems. A spike in 401 errors may point to expired credentials, bot traffic, or broken authentication. A spike in 403 errors may show role misconfiguration, abuse attempts, or users trying to access restricted resources.
Common Examples
The following examples show how the choice usually works:
- Missing Authorization header: 401.
- Expired JWT: 401.
- Invalid API key: 401.
- Valid user tries to delete another user without permission: 403.
- Logged-in customer tries to access an enterprise-only feature: 403.
- Valid token lacks the required
write:usersscope: 403.
There are edge cases. Some systems return 404 instead of 403 to hide that a resource exists. That can be sensible for private documents, user records, or security-sensitive endpoints. Still, if the server wants to say access is denied, 403 is the clearer code.
How 401 Should Be Designed
A good 401 response should help the client recover. It should not reveal sensitive details, but it should be clear enough for normal software flow.
A practical 401 body might look like this:
{
"error": "invalid_token",
"message": "The access token is expired or invalid."
}
The response should avoid saying too much, such as whether a username exists. For login forms, vague messages are safer. For APIs, structured error codes help client apps react without parsing human text.
How 403 Should Be Designed
A good 403 response should explain that access is blocked, not that login failed. It may also tell the user what to do next.
For example:
{
"error": "insufficient_permissions",
"message": "This account does not have permission to view billing reports."
}
For a SaaS product, the user interface might say, “Ask an administrator for billing access.” For a plan restriction, it might say, “This feature requires the Pro plan.” That is more useful than throwing the user back to a login form that changes nothing.
Best Practices for Teams
- Document the rules. Every API should define when it returns 401, 403, and 404.
- Keep token errors separate from permission errors. This improves debugging and support.
- Use consistent error bodies. Clients should receive predictable fields like
errorandmessage. - Log both categories. Track 401 and 403 rates separately.
- Do not expose secrets. Messages should help valid users without helping attackers.
FAQ
Is 401 the same as “not allowed”?
No. A 401 usually means the request has not been authenticated correctly. “Not allowed” is usually a 403 issue.
Should an expired token return 401 or 403?
An expired token should normally return 401. The client may be able to refresh the token or ask the user to sign in again.
Should a logged-in user without admin rights get 401?
No. If the user is logged in but lacks admin rights, the correct response is usually 403 Forbidden.
Can a server return 404 instead of 403?
Yes. Some systems return 404 to avoid revealing that a private resource exists. This is common for sensitive records or private files.
What is the biggest mistake with 401 and 403?
The biggest mistake is using 401 for every access failure. That causes bad login loops, broken token refresh behavior, and confusing support tickets.
