Utilo

HTTP 401 Unauthorized – Free, Online, Private

401 Unauthorized means the request lacks valid authentication, despite the name.

What HTTP 401 means

401 means the client is not authenticated for this resource. The response includes a WWW-Authenticate header that describes the challenge. The name is historical. The condition is unauthenticated, not 'you are forbidden'. A missing token, an expired token, and a bad signature are 401. A valid token that is not allowed to do the thing is 403.

401 Unauthorized belongs to the 4xx client error class. Clients that only look at the class will group it with its neighbors. Clients that care about the exact code should use the narrower rule on this page, because the class is only the first digit.

When you see HTTP 401

When you see HTTP 401 Unauthorized, stop on that exact status line. 401 Unauthorized means the request lacks valid authentication, despite the name. The trace that usually produces it: No Authorization header was sent. The 4xx client error class only tells you the first digit. A neighbor in that class is a different fault, and the fix on this page does not transfer to it.

Return 401 when the client must authenticate, and send WWW-Authenticate. Do not return 401 for a logged-in user who lacks permission. Do not return 401 with a body that says forbidden and no challenge. Clients and browsers use the challenge to decide how to ask for credentials.

How to fix HTTP 401

To fix HTTP 401, change the condition that made the server choose Unauthorized. Obtain fresh credentials and retry once. Do not tight-loop. If you have no way to authenticate, stop and surface the error. Sending the same header again will not help. Retry only with different credentials. An immediate retry of the same header is the same failure. If the log line is a different code, leave this page. The mix-up people make with 401 is this one: 403 is for an authenticated client that is not allowed. 407 is the same idea for a proxy. 400 is a malformed request, not a missing login.

  • The bearer token was expired or signed by the wrong key.
  • WWW-Authenticate was omitted, so a browser did not know how to prompt.
  • A client retried the same expired token in a loop.

An access log that only stores 401 is not enough to tell these apart. Keep the method, the path, and a request id. Do not keep the Authorization header or a request body that might be a token. The status explains the outcome. It is not a place to echo secrets back to the client either.

Example response

HTTP 401 UnauthorizedHTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="utilo"

WWW-Authenticate is the important header. The scheme might be Bearer, Basic, or something private. The body can explain the failure in JSON, but it does not replace the header. Do not reflect the bad token back in the body.

What the client should do

Obtain fresh credentials and retry once. Do not tight-loop. If you have no way to authenticate, stop and surface the error. Sending the same header again will not help.

A 401 must not be cached as a successful representation. Shared caches have special rules so one user's 401 is not stored as the resource. Mark it private if you are unsure.

Retry only with different credentials. An immediate retry of the same header is the same failure.

Codes people confuse with HTTP 401

403 is for an authenticated client that is not allowed. 407 is the same idea for a proxy. 400 is a malformed request, not a missing login.

Frequently asked questions

Why is it called Unauthorized if it means unauthenticated?

The name is historical. The condition is missing or invalid credentials.

Is WWW-Authenticate required?

Yes for a 401. It tells the client which scheme to use.

When is 403 correct instead?

When you know who the client is and they are not allowed to perform the action.

Should the expired token be in the body?

No. Say that it expired. Do not echo the secret.

What should I do first when I see HTTP 401?

Read the status as 401 Unauthorized specifically. 401 Unauthorized means the request lacks valid authentication, despite the name. Then check the cause that matches the request you sent, starting with: No Authorization header was sent.