pingrobot

HTTP status codes / 401

401 Unauthorized — HTTP Status Code

· 3 min read

Short answer

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_basic or Apache AuthType 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

  1. Expired tokens. OAuth access tokens and JWTs have short lifetimes. A client that does not refresh them starts getting 401s at a predictable interval.
  2. Header not forwarded. Some proxy and CGI/FastCGI setups do not pass the Authorization header to the app, so the app never sees the credentials.
  3. Wrong scheme. Sending Authorization: Token abc to an API that expects Bearer abc.
  4. Clock skew. Tokens with "not before" and expiry times can be rejected when the server's clock is off.
  5. 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.

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.