Skip to content
RU
← All articles

401 Unauthorized Error: What It Means and How to Fix It

A browser showing a username and password dialog over a blank page

A 401 Unauthorized error means the server refused the request because it carried no valid credentials: the token, API key, session cookie or password was missing, malformed, expired or sent in the wrong scheme. The fix is to send a fresh credential in the format the WWW-Authenticate response header asks for. Refreshing the page or clearing cache alone rarely helps.

This guide goes past the definition: how to read the challenge the server sends back, the exact places a valid token gets lost (Postman variables, redirects, nginx and Apache proxies, CORS preflights), how 401 differs from 403 and 407, and the checks that pin down the cause in a couple of minutes.

What does 401 Unauthorized mean?

Status 401 Unauthorized belongs to the 4xx class of client errors. Per RFC 9110, §15.5.2, it means the request "has not been applied because it lacks valid authentication credentials for the target resource." The name is misleading: despite the word "Unauthorized", this is about authentication — the server could not establish your identity. British sources often spell it "401 unauthorised"; it is the same status code.

The standard requires that a 401 response must include a WWW-Authenticate header with at least one challenge applicable to the resource. This header tells the client which authentication scheme to use. If the request already contained credentials, the 401 means they were rejected.

What an HTTP/1.1 401 Unauthorized response looks like

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

{ "error": "token_expired" }

Read the whole response, not just the status line. The scheme (Bearer), the realm, and the error parameter usually name the cause outright. Many APIs repeat it in the JSON body (token_expired, invalid_api_key, missing_authorization).

The role of the WWW-Authenticate and Authorization headers

HTTP authentication is a dialogue between two headers. First the server replies with 401 and a WWW-Authenticate challenge ("identify yourself this way"). Then the client repeats the request with an Authorization header carrying the credentials in the required scheme.

GET /api/profile HTTP/1.1
Host: example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

If Authorization is missing, wrong, or the token inside it has expired, the server returns 401 again. Browsers react to one scheme on their own: a WWW-Authenticate: Basic challenge makes Chrome, Edge, Firefox and Safari show a native username/password dialog. That is why single-page apps usually answer their own API calls with a Bearer challenge or a custom scheme, so a failed fetch does not pop up a login box.

Bearer error codes: 400, 401 or 403

For OAuth 2.0 bearer tokens, RFC 6750, §3.1 defines three error codes and the status each should use. They tell you whether to refresh the token or fix something else:

error= valueStatusWhat it meansWhat to do
invalid_request400Malformed request: missing parameter, token sent twiceFix how the request is built
invalid_token401Token expired, revoked, malformed or issued for another audienceRefresh or re-issue the token
insufficient_scope403Token is valid but lacks the scope the call needsRequest a token with the right scope
(no error parameter)401No credentials were sent at allAdd the Authorization header

What's the difference between 401 Unauthorized and 403 Forbidden?

These two codes are the most commonly confused. In short: 401 means "I don't know who you are" (an authentication problem), while 403 means "I know who you are, but you can't come in" (an authorization problem). The table below breaks down the differences and adds 407, which looks similar but comes from a proxy, not the site.

Aspect401 Unauthorized403 Forbidden407 Proxy Authentication Required
MeaningAuthentication failedAuthorization failedThe proxy between you and the site wants credentials
Who you are to the serverIdentity not establishedIdentity known (or irrelevant)Unknown to the proxy
When it occursMissing/wrong/expired credentialsInsufficient rights for the resource, IP or WAF ruleCorporate or ISP proxy requires login
Required headerWWW-Authenticate (mandatory)Not requiredProxy-Authenticate (mandatory)
Credentials go inAuthorization—Proxy-Authorization
Will logging in helpYes, re-authenticating may helpNo, logging in again won't change rightsYes, but to the proxy, not the site
What to doLog in again, refresh the tokenRequest access from an adminConfigure proxy credentials in the OS or client

A practical rule for API design: return 401 when the caller must authenticate (again), and 403 when authenticating again cannot change the outcome. Some sites deliberately return 404 instead of 403 to hide that a resource exists — that is allowed by the standard.

Authentication schemes: Basic, Bearer, Digest

The WWW-Authenticate header names the scheme. The most common are:

  • Basic — username and password encoded in Base64 (HTTPS only!). Authorization: Basic dXNlcjpwYXNz. Defined in RFC 7617.
  • Bearer — an access token (usually JWT or OAuth 2.0). Authorization: Bearer <token>
  • Digest — a hashed response to the server's challenge; never sends the password in the clear.
  • Negotiate / NTLM — Windows integrated authentication on IIS. Here the first one or two 401 responses are a normal part of the handshake, not an error; only a 401 at the end of the exchange is a failure.
  • Vendor schemes — some APIs define their own prefix, for example Discord bots send Authorization: Bot <token>. Sending the right token with the wrong prefix is still a 401.

Basic authentication example

curl -v https://example.com/private \
  -H "Authorization: Basic dXNlcjpwYXNzd29yZA=="

# the same, letting curl build the header
curl -v -u user:password https://example.com/private

How do I fix a 401 Unauthorized error?

Work from the cheapest check to the most involved. Stop as soon as one step explains the error.

  1. Read the challenge. Run the request with curl -i (or open DevTools → Network) and look at WWW-Authenticate and the response body. The scheme and error parameter narrow the cause.
  2. Confirm the header is actually sent. In curl use -v: lines starting with > are what went out. If there is no Authorization line, the problem is on the client, not the server.
  3. Check the scheme and format. Bearer with one space, no quotes, no duplicated prefix (Bearer Bearer eyJ... is a classic copy-paste bug), no trailing newline in a token read from a file.
  4. Check expiry. Decode the JWT and compare exp with the current UTC time. If it has passed, use the refresh token or log in again.
  5. Check that the credential belongs to this environment. A staging key sent to production, a token issued for another aud, or a revoked or rotated API key all look identical from the client: 401.
  6. Check what sits in between. Redirects, reverse proxies and CDNs can strip the header before the application sees it (see the sections below).
  7. Check the server's log. The auth layer usually logs the precise reason even when the response is deliberately vague.

How to clear error 401 as a website visitor

If you are not the developer and simply see "401 Unauthorized" in the browser:

  • Check the URL — a mistyped path can land in a password-protected area.
  • Log out and log in again, so the site issues a new session cookie.
  • Clear cookies for that one site (in Chrome: the site-information icon in the address bar → cookies and site data). Clearing the whole browser cache is rarely needed.
  • If the site uses a Basic Auth dialog, the browser remembers the credentials you typed for the session. After a password change, close all browser windows or open a private window to get a fresh prompt.
  • If it persists, the site owner has restricted the page. Only they can grant access.

Causes of a 401 error and how to fix it

Causes split into client-side and server-side.

  • Expired token or session — the most common cause with APIs. Fix: refresh the access token via the refresh token, or log in again.
  • Wrong credentials — a typo in the login/password, or a wrong API key. Fix: double-check the credentials.
  • Missing Authorization header — the client sent no credentials at all. Fix: add the header.
  • Wrong scheme — the server expects Bearer but the client sends Basic. Fix: match the WWW-Authenticate header.
  • Server configuration — for example, auth_basic is enabled in nginx or an API key is required.
  • API key in the wrong place — the API expects x-api-key as a header and you put it in the query string or body (or the other way round). Fix: follow the provider's docs to the letter; "missing API key" responses usually mean this.

Server-side Basic Auth in nginx

location /admin/ {
    auth_basic           "Restricted Area";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

With this configuration, any request to /admin/ without a valid Authorization header gets a 401 and a Basic challenge. The password file is created with htpasswd -c /etc/nginx/.htpasswd admin (from the apache2-utils or httpd-tools package; drop -c when adding a second user, or it overwrites the file). The nginx error log then states the exact reason: no user/password was provided for basic authentication, user "admin" was not found in "/etc/nginx/.htpasswd" or user "admin": password mismatch.

401 behind nginx and Apache: the header that never arrives

A token can be perfectly valid and still produce a 401 because the application never receives it:

  • Underscores in header names. nginx silently drops request headers that contain an underscore (api_key, X_Auth_Token) because underscores_in_headers is off by default. Rename the header to use hyphens, or enable the directive in the server block.
  • Apache with PHP-FPM or CGI. Apache does not pass Authorization to CGI and FastCGI back ends by default, so $_SERVER['HTTP_AUTHORIZATION'] is empty and the app answers 401. On Apache 2.4.13+ add CGIPassAuth On; on older setups the usual workaround is RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}].
  • A proxy that replaces the header. An nginx block with its own proxy_set_header Authorization ..., or an upstream protected with Basic Auth, overwrites the client's token.
  • Redirects. curl drops Authorization when a redirect leads to a different host (unless you pass --location-trusted), and most HTTP libraries do the same for safety. An API that redirects http:// to https:// or api.example.com to www.example.com therefore turns a valid request into a 401. Call the final URL directly.

CORS preflight returning 401

Before a cross-origin request with an Authorization header, the browser sends an OPTIONS preflight — and the preflight never carries credentials. If the server enforces authentication on OPTIONS too, the preflight gets a 401 and the browser reports a CORS error instead of the real call. Let OPTIONS through the auth layer and answer it with the CORS headers; see how CORS works for the full header set.

401 Unauthorized in Postman

Postman hides the headers it sends behind the Authorization tab, which is exactly why 401s there are confusing. Check in this order:

  • Auth type on the request. "Inherit auth from parent" uses the collection's or folder's settings; if the parent has "No Auth", nothing is sent.
  • Unresolved variables. If {{token}} is not defined in the selected environment, Postman sends the literal text. Check the environment selector in the top-right corner.
  • Duplicated prefix. With Auth type "Bearer Token", paste only the token — Postman adds Bearer itself.
  • A manual header fighting the Authorization tab. Remove one of them.
  • The Postman Console (opened from the status bar at the bottom of the window) shows the raw request that actually went out, including headers — the Postman equivalent of curl -v.
  • Redirects. If the endpoint redirects to another hostname, the request setting that follows the Authorization header on redirect decides whether the token survives.

Tokens and sessions: why a 401 hits logged-in users

The paradox "I logged in but I get a 401" is explained by the token lifecycle. In modern APIs the access token is deliberately short-lived — from a few minutes to an hour. This limits the damage if the token leaks. When it expires, the server responds with 401, and the client must exchange a long-lived refresh token for a new access token.

POST /oauth/token HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=def502...&client_id=app

A well-built client intercepts the first 401, refreshes the token automatically, and retries the original request — the user never notices the pause. Without this logic, the user sees a sudden logout. That is why handling 401 is a mandatory part of any API client. Two details matter in practice: refresh once and retry once (a second 401 after a refresh means the problem is not expiry, and looping will lock the account or hit rate limits), and serialize refreshes so ten parallel requests do not each burn the refresh token. The same logic applies to mobile apps: "401 unauthorized" on Android or iOS is almost always an expired or revoked token that the app failed to refresh. (The "unauthorized" state in adb devices is unrelated — it means the phone has not yet approved the computer's USB debugging key.)

Common server-side causes of a 401 in APIs

  • Key rotation — the old API key was revoked, but the app still sends it.
  • Clock skew — a JWT with an exp claim is seen as expired due to wrong server time. Check with timedatectl on Linux that the system clock is synchronized; the nbf ("not before") claim fails the same way when the issuer's clock runs ahead.
  • Wrong realm or audience — the token was issued for a different service.
  • Revoked session — an administrator forcibly ended the user's session.
  • Signing key mismatch — after rotating JWT signing keys, tokens signed with the old key fail verification until the verifier fetches the new key set.

To look inside a token, decode its payload and read exp, nbf, iss and aud; the structure and the verification steps are covered in JWT explained. Never paste production tokens into third-party websites to decode them.

401: Unauthorized on Discord and other platforms

For a Discord bot, "401: Unauthorized" from the API almost always means the bot token was reset in the Developer Portal or is sent without the Bot prefix. For end users of a desktop or web app, the same message usually clears after logging out and back in. On IIS, 401 has substatus codes in the server logs — for example 401.1 (logon failed) and 401.2 (logon failed due to server configuration) — which point at the credential or at the enabled authentication methods respectively.

How to check headers and authentication

To see the response code and the WWW-Authenticate header, use the free HTTP header and response code checker on enterno.io — it instantly shows the status and every response header. To assess the endpoint's overall security posture and the correctness of authentication schemes, our security scanner helps. Checking response headers is especially useful when you need to learn which scheme (Basic, Bearer, Digest) the server expects — that information always lives in the WWW-Authenticate challenge. If a valid token still ends in 401, run the URL through the redirect checker: a hop to another host or from HTTP to HTTPS is a common place where the Authorization header is dropped.

From a terminal, the same checks look like this:

# status line and all response headers, without the body
curl -sI https://api.example.com/v1/me

# full exchange: request headers (>) and response headers (<)
curl -v https://api.example.com/v1/me -H "Authorization: Bearer $TOKEN"

# just the status code, handy in scripts
curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com/v1/me

Note that -I sends a HEAD request; a few APIs handle HEAD differently from GET, so confirm with -v before drawing conclusions.

To master response codes, see the HTTP status code reference and the breakdown of the 403 Forbidden error, which is often confused with 401. It also helps to understand how HTTP headers work, since they carry the credentials. For the status code's reference definition, see MDN: 401 Unauthorized.

FAQ

What's the difference between 401 Unauthorized and 403 Forbidden?

401 Unauthorized means authentication failed: the server could not establish your identity because of missing, wrong, or expired credentials. 403 Forbidden means authorization failed: the server knows who you are but you lack sufficient rights. Re-authenticating helps with 401; with 403 only an administrator granting more rights will help.

Why do I get a 401 even though I am clearly logged in?

Most likely your access token or server session has expired. Access tokens are short-lived (minutes), and once they expire the server responds with 401. Refresh the token via the refresh token or log in again. Also verify that the Authorization header is actually being sent and holds a current value — proxies, redirects and CORS preflights can drop it on the way.

Is the WWW-Authenticate header mandatory in a 401 response?

Yes. Per RFC 9110, a server returning 401 must include a WWW-Authenticate header with at least one challenge applicable to the resource. It tells the client which authentication scheme to use — Basic, Bearer, Digest, and so on. A 401 without this header violates the standard.

How do I fix a 401 when calling an API?

Check in order: whether the Authorization header is sent, whether the scheme is correct (Bearer vs Basic), whether the token has expired, and whether the API key is valid. Run the request through curl -v to see the sent headers and the server response, including WWW-Authenticate with the error description.

How to clear error 401 in a browser?

Log out and back in, then clear cookies for that single site. For a Basic Auth prompt, close every browser window or use a private window so the browser forgets the credentials it cached. If the error remains, the page is restricted and only the site owner can grant access.

Is Basic authentication secure?

Basic sends the username and password merely Base64-encoded — that is reversible encoding, not encryption. It is acceptable only over HTTPS, where all traffic is encrypted by TLS. Without HTTPS the credentials are effectively sent in the clear. For APIs, the Bearer scheme with short-lived tokens is preferable.

Check your website right now

Check your site's HTTP status →
More articles: HTTP
HTTP
404 Not Found Error: Causes and Fixes for Chrome, nginx, Apache
15.04.2026 · 1 967 views
HTTP
HTTP Methods Explained: GET, POST, PUT, DELETE and Beyond
16.03.2026 · 978 views
HTTP
Server-Sent Events vs WebSockets: Which to Use for Realtime
16.03.2026 · 973 views
HTTP
The Complete HTTP Request Lifecycle: From URL to Rendered Page
16.03.2026 · 892 views