HTTP Status Codes Error 401: Unauthorized
The request has no valid credentials: the token is missing, malformed or expired. Send Authorization: Bearer <token>, and refresh the token on 401 before retrying once.
Identify: does your log match?
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","error_description":"The access token expired"}- High
Expired access token
Short-lived JWTs (often 5–60 min) expire while the client keeps using them. The server answers 401 with error="invalid_token".
- Medium
Authorization header stripped
A redirect to another host, a proxy or a CORS preflight drops the Authorization header, so the server sees an anonymous request.
- Medium
Wrong scheme or format
Sending the raw token without "Bearer ", using Basic for a Bearer API, or a stray newline in an env var.
Fix
Refresh once on 401, then retry
const res = await fetch('/api/me', { headers: { Authorization: token } });
async function api(path: string, init: RequestInit = {}, retried = false): Promise<Response> { const res = await fetch(path, { ...init, headers: { ...init.headers, Authorization: `Bearer ${getAccessToken()}` }, }); if (res.status === 401 && !retried) { await refreshAccessToken(); return api(path, init, true); } return res; }
A single refresh-and-retry handles expiry without loops. Prefix the token with the Bearer scheme.
Verify: reproduce it on purpose
$ curl -i https://httpbin.org/bearerRun it against a dev environment to trigger 401 on purpose and test your error handler.
Prevent
- Always return WWW-Authenticate with a 401.
- Refresh tokens proactively a minute before exp.
- Do not follow cross-origin redirects with credentials.
FAQ
What is the difference between 401 and 403?
401 means "who are you?" — authentication failed or is missing. 403 means "I know who you are, and you are not allowed".
Should a wrong password return 401?
For an API call with bad credentials, yes. A login form endpoint may also return 400 or 422 with a generic message.
Why do I get 401 only in production?
Often a reverse proxy strips Authorization or the env var holding the secret differs. Log whether the header is present (not its value).
Related errors
Last verified 2026-10-21 · Source: IANA HTTP Status Code Registry (RFC 9110) · Official docs ↗ · ~40,500 searches/mo