401 Unauthorized
4xx client error
The request lacks valid authentication credentials — the server doesn't know who you are.
Despite its name, 401 is about authentication, not authorization: the server doesn't know who you are. Either no credentials were sent, or the ones sent — token, cookie, API key — are missing, expired or invalid. The response must include a WWW-Authenticate header describing how to authenticate.
| Class | 4xx Client Error |
|---|---|
| Retry? | No — change the request first |
| Cacheable by default | No — only with explicit Cache-Control |
| Response body | Allowed |
| Defined in | RFC 9110 §15.5.2 — 401 Unauthorized |
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
Content-Type: application/json
Content-Length: 24
{"error":"Unauthorized"}Common causes
- No
Authorizationheader or session cookie was sent. - An expired or revoked access token (a JWT whose
expis in the past). - A token for the wrong environment or audience, such as a staging key on production.
- A proxy, redirect or CORS configuration stripping the
Authorizationheader.
How to fix it
- Decode the token and check its
exp,audandissclaims. - Refresh the access token and retry once; if that fails, send the user to log in again.
- Check the header format:
Authorization: Bearer <token>, with one space. - For cross-origin calls, make sure the server allows
AuthorizationinAccess-Control-Allow-Headers.
Useful here: 401 vs 403 · JWT Decoder
Send a 401 from your server
res.set("WWW-Authenticate", "Bearer realm=\"api\"");
res.status(401).json({ error: "Unauthorized" });return Response.json({ error: "Unauthorized" }, { status: 401, headers: { "WWW-Authenticate": "Bearer realm=\"api\"" } });return {"error": "Unauthorized"}, 401, {"WWW-Authenticate": "Bearer realm=\"api\""}w.Header().Set("WWW-Authenticate", "Bearer realm=\"api\"")
http.Error(w, "Unauthorized", http.StatusUnauthorized)add_header WWW-Authenticate "Bearer realm=\"api\"" always; return 401;
Check what a URL returns
Print just the status line from the command line, or check a whole list of URLs at once, with their response headers, in the HTTP Status Checker.
curl -sI https://example.com/your-path | head -n 1
Frequently asked questions
401 vs 403 — what's the difference?
401: we don't know who you are — authenticate and try again. 403: we know who you are, and you're not allowed. Logging in again fixes a 401; it won't fix a 403.
Why does a 401 open a browser login popup?
The response carried WWW-Authenticate: Basic, and browsers show their native credential dialog for Basic auth. APIs should use the Bearer scheme to avoid it.