HTTP status codes / 401
401 Unauthorized — HTTP Status Code
401 Unauthorized means the server did not accept the request because it came without valid authentication credentials, or the credentials it carried were rejected. Despite the name, it is about authentication (who you are), not permission (what you may do). A correct 401 response includes a WWW-Authenticate header telling the client how to authenticate.
What 401 means
RFC 9110 (Section 15.5.2) defines 401 Unauthorized as a request that was not applied because it lacks valid authentication credentials for the target resource. If the request did include credentials, the 401 means those credentials were refused.
The RFC adds a hard rule: a server sending 401 must include a WWW-Authenticate header with at least one challenge, such as Basic realm="admin" or Bearer. That header is what tells the client which scheme to use. A 401 without it is technically non-compliant, and some clients will not know what to do with it.
401 vs 403
The two are easy to mix up, so here is the short version:
| 401 Unauthorized | 403 Forbidden | |
|---|---|---|
| Question the server is answering | Who are you? | Are you allowed? |
| Will valid credentials help? | Yes | Not the same ones |
| Required header | WWW-Authenticate |
None |
| Typical cause | No token, expired token, wrong password | Role lacks access, IP blocked, WAF rule |
When you see it
- Web servers return 401 for paths protected with HTTP Basic auth, such as nginx
auth_basicor ApacheAuthType Basic. - APIs and API gateways return it for a missing, malformed or expired API key or bearer token.
- Staging environments often sit behind Basic auth or an identity-aware proxy so search engines and strangers cannot reach them.
- Applications return it when a session cookie has expired, although many web apps redirect to a login page (a 302) instead.
Common causes
- Expired tokens. OAuth access tokens and JWTs have short lifetimes. A client that does not refresh them starts getting 401s at a predictable interval.
- Header not forwarded. Some proxy and CGI/FastCGI setups do not pass the
Authorizationheader to the app, so the app never sees the credentials. - Wrong scheme. Sending
Authorization: Token abcto an API that expectsBearer abc. - Clock skew. Tokens with "not before" and expiry times can be rejected when the server's clock is off.
- Basic auth left on after a staging site was promoted to production.
How to fix it
First confirm what the server is asking for by reading the WWW-Authenticate header in the response. It names the scheme and often the realm or the error, for example Bearer error="invalid_token".
If credentials are being sent but ignored, check whether a proxy layer strips them. With Apache and PHP-FPM, a common fix is to pass the header explicitly:
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
If you return 401 from your own API, include the challenge so clients know what went wrong:
res.set("WWW-Authenticate", 'Bearer error="invalid_token"');
res.status(401).json({ error: "Access token expired" });
If a whole site unexpectedly asks for a password, look for leftover auth_basic or .htpasswd rules in the server config.
How to check it
Show the status line and the challenge header:
curl -sS -i https://api.example.com/v1/me | grep -iE "^HTTP|^www-authenticate"
Then repeat with credentials to confirm they are accepted:
curl -sS -o /dev/null -w "%{http_code}\n" \
-H "Authorization: Bearer $TOKEN" https://api.example.com/v1/me
What it means for uptime monitoring
PingRobot's checker sends a GET with the user agent PingRobot/1.0 (+https://pingrobot.io/bot) and no credentials, follows redirects, and treats the final response as up only if its status is 200 to 399. A 401 is reported as down.
In practice a 401 on a monitor almost always means the monitor is pointed at the wrong URL, not that the service is broken. Protected endpoints are supposed to reject anonymous requests. Monitor something public instead: the home page, a login page (which normally returns 200), or a dedicated health endpoint that requires no authentication and reveals no data.
The exception is a public page that suddenly starts returning 401. That usually means an auth rule or Basic auth block was deployed to the wrong environment, and real visitors are locked out too. That is a genuine outage worth an alert.
Related codes
- 403 Forbidden when the server refuses regardless of credentials
- 400 Bad Request for malformed requests
- 302 Found, the redirect many web apps use instead of 401
- 429 Too Many Requests when auth succeeds but you are rate limited
- 511 Network Authentication Required for captive portals
Start monitoring free — 10 monitors, no credit card.
Frequently asked questions
What is the difference between 401 and 403?
401 says the server does not know who you are, so log in or send valid credentials and try again. 403 says the server knows or does not care who you are and still refuses, so new credentials of the same kind will not help.
Why is it called Unauthorized if it means unauthenticated?
The name dates back to the early HTTP specifications and was kept for compatibility. RFC 9110 keeps the reason phrase but describes the code in terms of missing or invalid authentication credentials.
Should a login form return 401 for a wrong password?
Browser-based login forms usually re-render the page with an error and a 200 or redirect, because a 401 without a usable WWW-Authenticate challenge confuses some clients. JSON APIs commonly return 401 for a missing or expired token.
Why does my browser show a username and password pop-up?
The server returned 401 with a WWW-Authenticate header using the Basic or Digest scheme, which browsers answer with their built-in login dialog.