{ }HttpStatus.com

401 Unauthorized

The request lacks valid authentication credentials for the target resource; the server names an accepted scheme via WWW-Authenticate.

Defined in RFC 9110 §15.5.2

What 401 means

401 Unauthorized means the request lacks valid authentication credentials for the target resource, or the credentials supplied were rejected. Despite the name, it is about authentication, who you are, not authorization, what you're allowed to do, a subtlety the status name itself gets wrong. RFC 9110 requires that a 401 response include a WWW-Authenticate header naming at least one authentication scheme the server accepts, such as Basic, Bearer, or Digest, along with a realm identifying the protection space. A client that receives a 401 is expected to be able to retry the same request with credentials and succeed.

Modern APIs overwhelmingly authenticate with bearer tokens, typically JWTs, sent as Authorization: Bearer <token>. A 401 here usually means the token is missing, malformed, expired, or has been revoked; well-designed APIs distinguish these in the WWW-Authenticate header or response body using OAuth 2.0's Bearer error codes, such as error="invalid_token" for an expired JWT versus a simple absent header. JWT expiry is the single most common cause of 401s in production: the access token's exp claim has passed, and the client needs to use its refresh token to obtain a new one rather than treating the failure as fatal.

The 401-versus-403 distinction trips up many API designers. Use 401 when the server does not know who the caller is, or the credentials it received are invalid; the appropriate response is to authenticate or re-authenticate. Use 403 once the server does know who the caller is and has decided, based on that identity, to deny access regardless of credentials. Returning 403 for an unauthenticated request leaks information about resource existence without giving the client a path forward, while returning 401 for a permissions problem sends the client into a pointless login retry loop.

Browsers historically show a native credential prompt for 401 responses carrying a WWW-Authenticate: Basic header, which is why sites avoid Basic auth for user-facing pages. Single-page applications instead intercept 401 responses in an HTTP client interceptor, attempt a silent token refresh, and only redirect to a login screen if the refresh also fails. Clock skew between client and server is a quieter cause: if the server's clock is ahead, a token that looks valid to the client can appear expired to the server.

Common causes

  • The Authorization header is missing entirely from the request.
  • The bearer token or JWT has expired, meaning its exp claim is in the past.
  • The token was issued for a different audience, scope, or environment than the one being called.
  • The client used the wrong authentication scheme, such as sending Basic credentials to an endpoint expecting Bearer.
  • Session or auth cookies were not sent because of a SameSite or credentials:omit misconfiguration on a cross-origin request.
  • Clock skew between client and server causes a technically valid token to evaluate as expired or not-yet-valid.

How to fix a 401

If you are the client (browser user or API caller)

  • Attach a valid Authorization header with the correct scheme, Bearer, Basic, or otherwise, on every request.
  • Use the refresh token to obtain a new access token before retrying, instead of surfacing the failure to the user immediately.
  • Confirm the token's audience and scope match the endpoint being called.
  • Set credentials: 'include', or the SDK equivalent, so auth cookies are sent on cross-origin requests.
  • Re-authenticate the user and persist the new token if the refresh attempt also fails.

If you run the server

  • Always include a WWW-Authenticate header naming the accepted scheme and realm on every 401 response.
  • Return 401, not 403, whenever the caller's identity is unknown or the credentials themselves are invalid.
  • Support short-lived access tokens paired with a refresh flow, and surface a distinct error code for expiry versus revocation.
  • Switch to 403 once identity is established but the action is disallowed, to avoid confusing clients about what went wrong.
  • Allow a small clock-skew tolerance, a few minutes, when validating JWT exp and nbf claims.

Example

GET /api/account HTTP/1.1
Host: api.example.com

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api", error="invalid_token", error_description="The access token expired"
Content-Type: application/json

{"error": "invalid_token", "message": "Access token expired at 2026-09-04T10:00:00Z"}
The WWW-Authenticate header tells the client exactly which scheme applies and why the token was rejected.

Try it live

Our free status responder returns a real HTTP 401 you can point tests, monitors or a browser at.

GET https://mcp.httpstatus.com/status/401

Related status codes

Tools for debugging this