HTTP 401

401 Unauthorized

Client Error

The request lacks valid authentication credentials for the target resource. 401 indicates the server does not know who you are. The credentials are missing, malformed, or have expired. The response must include a WWW-Authenticate header describing the authentication scheme(s) the server expects, although in practice many APIs omit it. Despite the name, 401 has nothing to do with authorization in the access-control sense; it is purely about authentication. Use 403 when the identity is known but lacks permission.

When does this happen?

Return 401 when the server cannot identify the caller. The Authorization header is missing entirely, the bearer token is malformed, the API key is unknown, the session cookie has expired, or the JWT signature failed verification. Browsers respond to 401 by triggering the native HTTP authentication prompt only when the response includes a WWW-Authenticate: Basic or WWW-Authenticate: Digest header. Modern APIs almost always avoid that header to suppress the prompt. For cookie-based sessions, the convention is that the client should redirect to a login page on receiving 401. The response can include details about why authentication failed ("token expired" vs "signature invalid" vs "key revoked") but should not leak whether a specific username exists, which would help account enumeration attacks. 401 is also the right answer when a token has expired and the client should refresh it. Exposing this distinction through the response body lets SDKs trigger token refresh automatically.

Common causes

How to fix it

Real-world examples

Client calls GET /v1/me without an Authorization header.
Server returns 401 with WWW-Authenticate: Bearer and body {"error":"missing credentials"}. SDK prompts user to log in.
Access token expired one minute ago and the client did not refresh before retrying.
Server returns 401 with {"error":"token_expired"}. Client uses its refresh token to obtain a new access token and retries the original request transparently.
User logs out in one tab and an open API call in another tab uses the now-invalid session cookie.
Server returns 401. Frontend catches it and redirects the user to /login.
Developer copies an API key from a screenshot but the trailing equals sign is missing.
Server returns 401 because the key does not match anything in the database. Developer regenerates and copies the full key.
JWT was signed with an old key after a rotation.
Server returns 401 with signature_invalid in the error body. The client must obtain a fresh token signed with the current key.

Debugging

How it differs from related codes

HTTP 403

401 means we do not know who you are. 403 means we know who you are but you are not allowed to do this. Re-authenticating fixes 401; it will not fix 403.

HTTP 407

407 is identical to 401 in semantics but applies to authentication against a proxy rather than the origin server. The header used is Proxy-Authenticate instead of WWW-Authenticate.

HTTP 404

Some APIs return 404 instead of 401/403 for protected resources to avoid leaking existence. Conceptually 401 says "not authenticated" while 404 says "no such resource". Security trade-off, not interchangeable.

Related status codes

400 403 405 422 429

See HTTP 401 in your redirect chains?

Check your URLs with checkredirects.io