401 Unauthorized & 401 Authorization Required: How to Fix

Key takeaway

HTTP 401 Unauthorized means the server needs you to prove who you are, and your request either didn't or used credentials it rejected. "401 Authorization Required" is the same code on nginx's default page, usually a password-protected area. As a visitor, sign in again with the right details, clear the site's cookies, or ask the owner for access. As a developer, check the Authorization header ("Bearer <token>"), that the key or token hasn't expired, and what the WWW-Authenticate header asks for.

Check it now

HTTP 401 Unauthorized error fix guide showing authentication failure causes and step-by-step solutions
HTTP 401 Unauthorized error fix guide showing authentication failure causes and step-by-step solutions
Start reading
  1. What Is a 401 Unauthorized Error?
  2. What a 401 Error Looks Like
  3. "401 Authorization Required" on nginx
  4. 401 vs 403: What's the Difference?
  5. Common Causes of 401 Errors
  6. How to Fix 401 as a Visitor
  7. 1. Check Your Login Credentials
  8. 2. Clear Browser Cache and Cookies
  9. 3. Try Incognito or Private Mode
  10. 4. Verify the URL
  11. How to Fix 401 as a Developer
  12. 5. Verify the Authorization Header
  13. 6. Check API Key Validity
  14. 7. Handle Token Expiry and Refresh
  15. 8. Fix CORS Preflight Issues
  16. How to Fix 401 as a Site Owner
  17. 9. Review Server Authentication Config
  18. 10. Check .htaccess Authentication Rules
  19. 11. Make Sure the Authorization Header Reaches Your App
  20. Debugging 401 Errors with HTTP Headers
  21. Does a 401 Error Affect SEO?
  22. How to Prevent 401 Errors
  23. Frequently Asked Questions

What Is a 401 Unauthorized Error?

A 401 Unauthorized error means the server needs you to prove who you are, and your request didn't, or the credentials it carried were rejected. No password, a wrong password, an expired token or a missing API key all end the same way.

The HTTP standard defines it as a request that "lacks valid authentication credentials for the target resource", and a server sending a 401 MUST include a WWW-Authenticate header that says which login scheme it accepts (RFC 9110 §15.5.2).

In plain terms, the server is asking "who are you?" before it lets you in.

See a URL's status code and WWW-Authenticate header

What a 401 Error Looks Like

The page you see depends on the server and the app:

  • 401 Unauthorized — the standard status line, and most apps' wording
  • 401 Authorization Required — the title of nginx's built-in 401 page, with "nginx" (usually with its version) underneath (nginx source); old Apache 2.2 servers use the same words
  • Unauthorized · This server could not verify that you are authorized to access the document requested — Apache's default page
  • 401 - Unauthorized: Access is denied due to invalid credentials — IIS; the detailed page (shown on the server itself) and the IIS log give the reason as 401.1, 401.2 or 401.3: logon failed, server configuration, or file permissions
  • A sign-in box in the browser — when the server asks for HTTP Basic or Digest authentication, or (on IIS and company intranets) NTLM or Negotiate
  • This page isn't working · HTTP ERROR 401 — Chrome, when the 401 response has no page of its own
  • JSON from an API, such as {"error":{"message":"Missing Authentication header","code":401}}

Browsers show the sign-in box only for those login schemes. Token-based APIs ("Bearer") never trigger it; their 401 comes back as JSON for the app to handle. Websites with a login form usually send a signed-out visitor to the login page with a 302 redirect instead of a 401.

"401 Authorization Required" on nginx

That title comes from nginx's built-in 401 page. You get it when a location is protected with auth_basic and the request carried no username and password, or the wrong ones; cancelling the browser's sign-in box shows this page too.

As a visitor, reload and enter the username and password the site's owner gave you. They're separate from any account on the site: Basic authentication checks a password file on the server.

As the site's owner, this is how the protection is set up, and how to keep a path public:

nginx
# Create the password file (htpasswd comes with apache2-utils or httpd-tools)
#   sudo htpasswd -c /etc/nginx/.htpasswd alice   # -c creates the file: leave it out when adding users

location /admin/ {
    auth_basic           "Admin area";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

# Inside a protected server block, open one path to everyone
location /public/ {
    auth_basic off;
}

# Test, then reload
#   curl -I -u alice:PASSWORD https://example.com/admin/
#   sudo nginx -t && sudo systemctl reload nginx

Still 401 with the right password? Check that the user is in the file (htpasswd -c overwrites the file, removing earlier users), and that the app behind nginx doesn't need the Authorization header too: nginx's Basic login and an app's Bearer tokens both use it, so the app receives nginx's credentials and rejects them.

401 vs 403: What's the Difference?

The 401 and 403 codes are often confused. The short version: 401 means "I don't know who you are", while 403 means "I won't let you in", whether or not your identity is the problem.

Aspect401 Unauthorized403 Forbidden
Core meaningAuthentication failed or missingAuthorization denied
The server's question"Who are you?""You do not have permission"
CredentialsNot provided or invalidValid but insufficient, or not the issue (IP block, firewall, file permissions)
Can retrying help?Yes, with the right credentialsNot with the same credentials
WWW-Authenticate headerRequired by the spec (many APIs skip it)Optional (e.g. Bearer error="insufficient_scope")
Example scenarioAccessing admin panel without logging inLogged in as viewer, trying to delete posts

A practical rule: if providing the right username and password (or API key) would fix it, the server should return 401. If the user is already authenticated but simply does not have access to that resource, the server should return 403 Forbidden.

Common Causes of 401 Errors

The causes, from the visitor's side to the server's:

  • Wrong username or password — the most basic cause, especially after a password reset
  • Expired authentication token — JWT tokens, OAuth access tokens, and session cookies all have expiry times
  • Missing Authorization header — the request did not include any credentials at all
  • Invalid API key — the key was revoked, rotated, or copied incorrectly
  • Incorrect auth scheme — server expects Bearer token but received Basic auth, or vice versa
  • Clock skew — the server that checks a JWT and the one that issued it (or your machine, if it signs the JWT) disagree on the time; many libraries allow no leeway at all
  • A CORS preflight — the browser's OPTIONS check never carries credentials, so a server that demands them answers 401 and the real request is never sent
  • A stale session — the browser sends a session cookie the server has already ended
  • Something in between drops the header — Apache hides Authorization from PHP-FPM and CGI scripts unless told otherwise, CloudFront removes it from GET and HEAD requests by default, and nginx Basic auth in front of an app takes it over
  • Locked or revoked credentials — too many failed attempts can lock an account (some APIs answer that with 429 Too Many Requests instead)

How to Fix 401 as a Visitor

If you encounter a 401 error on a website you are trying to access, the issue is almost always related to your login credentials. Follow these steps in order.

1. Check Your Login Credentials

The most common cause of a 401 error is simply wrong credentials. If the site shows a login popup or form, double-check your username and password.

Common mistakes: Caps Lock is on, you are using an old password (especially after a recent reset), or you are logging into the wrong account. If you have a password manager, let it auto-fill the credentials to avoid typos.

2. Clear Browser Cache and Cookies

Your browser may be sending an expired session cookie. Deleting the site's cookies makes it ask for a fresh login.

text
Chrome, Edge, Firefox: Ctrl+Shift+Delete (Cmd+Shift+Delete on a Mac)
  → Time range: All time → Cookies and site data + Cached files → Delete / Clear
  (this signs you out of every site; the per-site option below doesn't)
Safari: Settings → Privacy → Manage Website Data → the site → Remove
One site in Chrome: the icon left of the address → Site settings → Delete data

After clearing, close the browser completely (not just the tab), reopen it, and navigate to the page again. You should see a fresh login prompt.

3. Try Incognito or Private Mode

Open the URL in an incognito (Chrome) or private (Firefox/Safari) window. This bypasses all cached cookies, extensions, and stored credentials.

If the page works in incognito but not in your regular browser, the problem is a cached cookie or a browser extension interfering with authentication. Disable extensions one by one to find the culprit.

4. Verify the URL

Make sure you are visiting the correct URL. Some servers return 401 for paths that require authentication, even if the path itself is wrong. You might be trying to access a restricted area you were not meant to visit.

Check if there is a public version of the page at a different URL. For example, example.com/admin/ might return 401 while example.com/ is publicly accessible.

Not sure the site works at all? The Website Down Checker opens it from 11 places, so you can tell a login problem from an outage.

How to Fix 401 as a Developer

For developers working with APIs, 401 errors are usually about the Authorization header, token format, or credential lifecycle. These are the most common fixes.

5. Verify the Authorization Header

The most common developer mistake is a malformed Authorization header. When the server sends a WWW-Authenticate header, it names the scheme it expects; many JSON APIs (GitHub's and OpenRouter's, for example) leave it out and explain the problem in the response body instead.

Check that your header matches the required format. The most common schemes are Bearer (for tokens) and Basic (for username:password encoded in Base64).

bash
# Bearer token authentication (most APIs)
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." https://api.example.com/data

# Basic authentication (username:password in Base64)
curl -u "username:password" https://api.example.com/data
# Equivalent to:
curl -H "Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=" https://api.example.com/data

# Common mistakes that cause 401:
# Missing "Bearer " prefix:  Authorization: eyJhbGci...  ← WRONG
# Extra space:               Authorization: Bearer  eyJ... ← many servers reject it
# Wrong scheme:              Authorization: Basic eyJhbGci... ← WRONG

Then read the WWW-Authenticate header in the 401 response: it names the scheme the server expects. DNS Robot's HTTP Header Checker shows the full response.

6. Check API Key Validity

API keys stop working when the key is rotated or revoked, the account is suspended or downgraded, or a test key is used against production. (A rate limit answers 429, and a key without access to an endpoint usually gets 403.)

Check that the key is still active in the provider's dashboard, then test it directly:

bash
# Test a key: print only the status code (a real GET; some APIs reject HEAD)
curl -s -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer YOUR_API_KEY" https://api.example.com/me
# 200 = the key works
# 401 = the key is missing, wrong, revoked or expired
# 403 = the key works but isn't allowed to use this endpoint

# Common slips:
# 1. A space or newline after the key in .env:   API_KEY="abc123 "
# 2. The test key in production, or the reverse
# 3. An empty variable, so the header is just "Authorization: Bearer"

7. Handle Token Expiry and Refresh

JWT tokens and OAuth access tokens have a limited lifetime — typically 15 minutes to 24 hours. When they expire, every API call returns 401 until you get a fresh token.

If you have a refresh token (OAuth 2.0 and most JWT setups), exchange it for a new access token; without one, sign in again.

bash
# Read a JWT's payload (tokens use base64url, so plain base64 -d often fails)
python3 -c 'import sys,base64,json; p=sys.argv[1].split(".")[1]; print(json.dumps(json.loads(base64.urlsafe_b64decode(p+"==")),indent=2))' "$TOKEN"
# "exp" is a Unix timestamp; compare it with: date +%s

# OAuth 2.0: get a new access token with the refresh token
curl -X POST https://auth.example.com/token \
  -d "grant_type=refresh_token" \
  -d "refresh_token=YOUR_REFRESH_TOKEN" \
  -d "client_id=YOUR_CLIENT_ID"

8. Fix CORS Preflight Issues

When a web page calls an API on another domain with an Authorization header, the browser first sends a preflight OPTIONS request, and the preflight never carries credentials. If the server demands authentication on OPTIONS, it answers 401, the preflight fails, and the browser reports a CORS error: the real request is never sent.

The fix: let OPTIONS requests through without authentication on CORS-enabled endpoints.

nginx
# Nginx — allow OPTIONS requests without auth
location /api/ {
    if ($request_method = OPTIONS) {
        add_header Access-Control-Allow-Origin https://app.example.com;
        add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
        add_header Access-Control-Allow-Headers "Authorization, Content-Type";
        add_header Access-Control-Max-Age 86400;
        return 204;
    }

    # CORS header on every other answer, the 401 included, or the browser reports a CORS error
    add_header Access-Control-Allow-Origin https://app.example.com always;

    # Normal auth for other methods
    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

How to Fix 401 as a Site Owner

If your visitors or users are reporting 401 errors, the problem is in your server's authentication configuration. Work through these checks.

9. Review Server Authentication Config

Check that authentication is only enabled on the routes that need it. A common mistake is protecting an entire directory or site when only specific paths should require login.

On nginx, check your auth_basic directives; on Apache, AuthType and Require. On Node.js/Express, check your middleware order: an app.use(auth) registered before your public routes protects them too, so register public routes first or attach auth only to the protected router.

nginx
# Nginx — WRONG: protects everything, including public pages
server {
    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;
    # All pages now require login — including your homepage!
}

# Nginx — CORRECT: only protect admin routes
server {
    location / {
        # Public — no auth required
    }
    location /admin/ {
        auth_basic "Admin Area";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }
}

10. Check .htaccess Authentication Rules

On Apache, .htaccess files can turn on Basic or Digest authentication for a directory. If a public directory has a .htaccess with AuthType and Require directives, every visitor gets a 401 login prompt.

Check for .htaccess files in the affected directory and all parent directories — Apache applies rules from every .htaccess in the path.

bash
# Find all .htaccess files with auth rules
find /var/www/html -name '.htaccess' -exec grep -l 'AuthType\|AuthUserFile\|Require valid-user' {} \;

# Example .htaccess that causes 401 for everyone:
# AuthType Basic
# AuthName "Restricted Area"
# AuthUserFile /etc/apache2/.htpasswd
# Require valid-user

# Fix: remove auth lines from public directories,
# or move them to the specific /admin/.htaccess only

11. Make Sure the Authorization Header Reaches Your App

The client sends correct credentials, but the app never sees them. Where the header gets lost:

nginx forwards Authorization to the backend by default, so you don't need extra lines; but if the same location uses auth_basic, nginx's login takes over the header (see the nginx section above). Apache hides Authorization from PHP-FPM and CGI scripts unless you turn on CGIPassAuth (Apache 2.4.13+), the classic cause of 401s in WordPress and Laravel APIs behind Apache.

apache
# Apache 2.4.13+ (inside a <Directory> block, or .htaccess): pass Authorization to PHP-FPM and CGI
CGIPassAuth On

# Older Apache: copy it into an environment variable instead
SetEnvIf Authorization "(.+)" HTTP_AUTHORIZATION=$1

Debugging 401 Errors with HTTP Headers

The fastest way to diagnose a 401 is to read the response: the WWW-Authenticate header, when the server sends it, says which login it wants, and JSON APIs usually explain the error in the body.

Use DNS Robot's HTTP Header Checker (if the 401 only appears after a redirect, the Redirect Checker shows which hop answers it), or curl from a terminal:

bash
# Print the response headers of a real GET
curl -sS -D - -o /dev/null https://api.example.com/protected-endpoint

# A 401 often carries one of:
# WWW-Authenticate: Bearer realm="api", error="invalid_token"
# WWW-Authenticate: Basic realm="Admin Area"

# It tells you:
# - the scheme (Bearer, Basic, Digest, Negotiate)
# - the realm (which area is protected)
# - for Bearer tokens, the error: invalid_request, invalid_token or insufficient_scope

If WWW-Authenticate says Bearer, you need a token; if it says Basic, a username and password. error="invalid_token" means the token is expired, revoked, malformed or otherwise invalid. No header at all? Read the response body: many APIs put the reason there.

Does a 401 Error Affect SEO?

A 401 on a public page takes it out of Google. Google treats every 4xx code except 429 the same way: the crawler reports that the content doesn't exist, and an indexed URL is removed (Google's crawler documentation).

401s on pages that should need a login (admin panels, dashboards, APIs) are normal: Google doesn't penalize a site for them. Just don't use 401 or 403 to slow Googlebot down; Google says they have no effect on crawl rate.

The problem is a 401 on pages that should be public, usually from authentication applied to a whole site, or a CDN or proxy rule asking for credentials on public paths.

How to Prevent 401 Errors

Prevention saves you from debugging later. Follow these practices to minimize 401 errors in your applications and websites.

  • Implement token auto-refresh — use refresh tokens to silently get new access tokens before they expire
  • Set proper auth scopes — only protect routes that genuinely need authentication, keep public pages open
  • Use clear error messages — return helpful JSON error bodies alongside 401, not just the status code
  • Monitor auth failures — set up alerts for spikes in 401 responses, which may indicate credential issues or attacks
  • Sync server clocks — use NTP to keep all servers within a few seconds of UTC, preventing JWT clock-skew rejections
  • Test with the HTTP Header Checker — regularly verify that public pages return 200 and protected pages return 401 as expected
  • Document your auth scheme — make the expected Authorization header format clear in your API documentation
  • Handle CORS preflight — always allow OPTIONS requests without authentication on API endpoints

See the 401 and its WWW-Authenticate header

DNS Robot's free HTTP Header Checker shows any URL's status code and response headers, including WWW-Authenticate, which names the login scheme the server expects.

Sources

  1. RFC 9110 §15.5.2: 401 Unauthorized, IETF
  2. ngx_http_special_response.c (nginx's 401 page), nginx
  3. CGIPassAuth directive, Apache
  4. HTTP status codes and Google's crawlers, Google

Frequently Asked Questions

What does a 401 error mean?

The server needs valid credentials and your request didn't include them, or included ones it rejected: no password, a wrong password, an expired token or a missing API key. It's a request to prove who you are, not a ban.

What does "401 Authorization Required" mean?

It's usually nginx's built-in 401 page (old Apache 2.2 servers use the same words). The page is protected with a username and password (HTTP Basic authentication) and your browser sent none or the wrong ones. Reload and enter the credentials the site's owner gave you; they're separate from any account on the site.

What is the difference between 401 and 403?

A 401 means the server doesn't know who you are: sign in or send valid credentials and it can work. A 403 means it knows who you are, or doesn't care, and still refuses; sending the same credentials again won't help.

How do I fix a 401 Unauthorized error?

As a visitor: check your username and password, delete the site's cookies and sign in again, or try a private window. As a developer: check the Authorization header ("Bearer <token>" with one space), that the key or token hasn't expired or been revoked, and what the WWW-Authenticate response header asks for.

Why am I getting 401 on my API call?

Usually the Authorization header is missing or malformed (no "Bearer " prefix, or an empty variable), the key was rotated or revoked, the token expired, or something between you and the app dropped the header: Apache without CGIPassAuth, CloudFront's defaults for GET and HEAD, or nginx Basic auth taking it over.

What does "proxy error 401: Missing Authentication header" mean?

It's the error OpenRouter's API returns when the Authorization header doesn't hold an OpenRouter key in the form "Bearer sk-or-v1-…": it's empty, says undefined, or holds another provider's key (an OpenAI sk-… key gets the same message; we tested in October 2026). AI chat apps that connect through it show it as a proxy error. Paste your OpenRouter key, which starts with sk-or-v1-, and save.

What is the WWW-Authenticate header?

The response header the standard requires on every 401. It names the login scheme the server accepts (such as Basic, Digest, Bearer or Negotiate) and can add a realm and an error, such as error="invalid_token". Many JSON APIs leave it out and explain the error in the response body instead.

Can a 401 error be caused by CORS?

Yes. Before a cross-origin request with an Authorization header, the browser sends an OPTIONS preflight without credentials. If the server demands authentication on OPTIONS, it answers 401, the preflight fails and the browser shows a CORS error. Let OPTIONS through without authentication.

How do I check if my token is expired?

For a JWT, decode the middle part (base64url) and read the "exp" field, a Unix timestamp, then compare it with the current time (date +%s). For other OAuth tokens, use your provider's token introspection endpoint if it has one.

Why does my browser show a login popup for 401?

Because the server's 401 carries WWW-Authenticate: Basic or Digest (or NTLM/Negotiate on IIS and intranets), and browsers answer that with their built-in sign-in box. Cancelling it shows the server's 401 page. Apps that use tokens never trigger the box.

About the author

Shaik Vahid

Founder of DNS Robot. Vahid spent years in web hosting support fixing domains, DNS records, SSL certificates and email delivery for customers. He builds DNS Robot's tools and writes these guides from the errors people actually hit.

HTTP Header Checker

Response headers exactly as sent, with a Mozilla Observatory security grade