Last tested: October 22, 2026 · By Alex
A 401 Unauthorized error means the server needs valid authentication for the resource you requested, and the request either did not include credentials or included credentials the server rejected. Despite the name, it is about authentication (who you are), not authorization (what you are allowed to do).
On real sites, 401 errors usually come from HTTP Basic Auth on a staging or admin directory, an expired or malformed API token, a WordPress REST API request without proper credentials, or a server that strips the Authorization header before it reaches PHP.
Quick Fix
- Check that the URL is correct and that you are supposed to log in to see it.
- Re-enter the username and password carefully (watch for keyboard layout and Caps Lock).
- Log out and log back in to refresh the session.
- Clear cookies for the site and try a private window.
- For APIs, generate a fresh token or Application Password and check the
Authorizationheader format. - If you run the server, check the
.htpasswdpath and file permissions. - Confirm the server passes the
Authorizationheader to PHP. - Check security plugins, Cloudflare Access, or WAF rules that may require authentication.
What Is 401 Unauthorized?
401 Unauthorized is an HTTP client error status code. A correct 401 response includes a WWW-Authenticate header that tells the client which authentication scheme to use, for example:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Restricted Area"
When a browser sees Basic, it shows the native login popup. APIs often send WWW-Authenticate: Bearer instead, which tells the client a token is expected.
How it differs from related codes:
- 401 Unauthorized: you are not authenticated, or your credentials are invalid. Logging in may fix it.
- 403 Forbidden: the server knows who you are (or does not care) and still denies access. Logging in again will not help.
- 407 Proxy Authentication Required: the same idea as 401, but a proxy between you and the server wants credentials.
Why 401 Unauthorized Happens
1. Wrong or Missing Credentials
The simplest cause. A mistyped password, an old saved password in the browser, or a script that never sends credentials at all.
2. HTTP Basic Auth on a Directory
Hosts and developers often protect /wp-admin/, staging sites, or private folders with .htpasswd. If the password file path is wrong or the user entry is missing, every login attempt fails with 401.
3. Expired or Invalid API Tokens
JWTs expire, OAuth access tokens expire, and API keys get rotated. A request with an old token gets 401. A wrong header format, such as Bearer missing or an extra space, has the same effect.
4. Authorization Header Stripped by the Server
On many Apache + PHP-FPM or CGI setups, the Authorization header is not passed to PHP by default. The client sends correct credentials, but WordPress or your app never sees them and returns 401.
5. WordPress REST API Without Proper Auth
Endpoints that create, update, or read private data require authentication. Cookie authentication also requires a valid nonce in the X-WP-Nonce header. Without it, WordPress returns rest_not_logged_in or rest_cookie_invalid_nonce.
6. Security Plugins, WAF, or Access Layers
Cloudflare Access, hosting-level password protection, or security plugins that disable the REST API for anonymous users can return 401 even when the page itself is public.
7. Cached 401 Responses
If a cache layer stores a 401 response, visitors may keep seeing it after the problem has been fixed.
How to Fix 401 Unauthorized Step by Step
1. Confirm the URL and Credentials
Make sure you are on the right domain and path. Then type the credentials manually instead of using autofill. Saved browser passwords are a frequent source of silent failures after a password change.
2. Clear Cookies and Log In Again
Delete cookies for the site, close the tab, and sign in again. For Basic Auth, browsers cache credentials for the session. Closing all browser windows or using a private window forces a fresh prompt.
3. Inspect the Response Headers
curl -I https://example.com/protected/
Look for WWW-Authenticate. If it says Basic, the server or host is using password protection. If it says Bearer, the app expects a token. If there is no such header, the 401 probably comes from application code or a plugin.
4. Test Credentials with curl
# Basic Auth
curl -i -u "username:password" https://example.com/protected/
# Bearer token
curl -i -H "Authorization: Bearer YOUR_TOKEN" https://api.example.com/v1/me
If curl works and the browser does not, the problem is in the browser session or saved credentials. If curl also fails, the credentials or server config are wrong.
5. Check .htpasswd and .htaccess (Apache)
A typical password-protected directory looks like this:
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /home/username/.htpasswds/.htpasswd
Require valid-user
Common mistakes: a relative AuthUserFile path (it must be absolute), a file the web server user cannot read, or a user that was never added. Create or update a user with:
htpasswd /home/username/.htpasswds/.htpasswd alex
# use -c only when creating a new file, it overwrites existing ones
6. Check auth_basic in NGINX
location /wp-admin/ {
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
# don't lock out AJAX requests from the frontend
location = /wp-admin/admin-ajax.php {
auth_basic off;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
Create the password file with sudo htpasswd -c /etc/nginx/.htpasswd alex (install apache2-utils on Debian/Ubuntu if the command is missing), then run sudo nginx -t && sudo systemctl reload nginx. Adjust the PHP-FPM socket path to your server.
7. Refresh API Tokens
Generate a new token or key in the provider dashboard and update it everywhere it is stored: environment variables, plugin settings, CI secrets. Decode a JWT at the command line to check its expiry claim (exp) before blaming the server.
Advanced Troubleshooting
Pass the Authorization Header to PHP
If credentials are correct but WordPress or your app still returns 401, the header is likely being dropped. On Apache, add this above the WordPress block in .htaccess:
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
On Apache 2.4.13+ you can use this instead:
CGIPassAuth On
On NGINX with PHP-FPM, fastcgi_params normally passes HTTP_AUTHORIZATION automatically. If a custom config overrides it, add:
fastcgi_param HTTP_AUTHORIZATION $http_authorization;
Debug With a Simple PHP Check
Upload a temporary file and request it with credentials:
<?php
var_dump($_SERVER['HTTP_AUTHORIZATION'] ?? 'missing');
var_dump($_SERVER['PHP_AUTH_USER'] ?? 'missing');
If both say missing, the server is stripping the header. Delete the file right after testing.
Check Reverse Proxies
Load balancers and proxies sometimes drop or rewrite Authorization. In NGINX as a reverse proxy, the header is forwarded by default unless something like proxy_set_header Authorization ""; is set. Check every layer between the client and the app.
WordPress-Specific Causes
- Application Passwords: For external apps and scripts, create one under Users → Profile → Application Passwords and use it with Basic Auth:
curl -u "alex:xxxx xxxx xxxx xxxx xxxx xxxx" https://example.com/wp-json/wp/v2/users/me. They require HTTPS unless the site is in a local environment. - REST API nonces: Custom JavaScript using cookie auth must send
X-WP-Noncecreated withwp_create_nonce( 'wp_rest' ). An expired page left open for a long time can causerest_cookie_invalid_nonce. Reload the page. - Security plugins: Plugins that disable the REST API for logged-out users return 401 for public endpoints too. That can break contact forms, search, or headless frontends. Whitelist the routes you need.
- Basic Auth on wp-admin: If you protect
/wp-admin/, excludeadmin-ajax.php, or frontend features using AJAX will fail. - Staging sites: Hosts often password-protect staging copies. A 401 there is expected until you enter the staging credentials from the hosting panel.
The Cloudflare Angle
Cloudflare does not create 401 responses on its own for normal proxied traffic. A 401 usually comes from your origin, but check these first:
- Cloudflare Access (Zero Trust): protected applications redirect to a login page or return 401 for API clients without a valid service token.
- Workers: a Worker can enforce auth and return 401 itself. Check Workers routes for the hostname.
- Caching: make sure authenticated or 401 responses are not cached by a “Cache Everything” rule. Bypass cache for
/wp-admin/,/wp-json/, and logged-in cookies.
To isolate the origin, test directly: curl -i --resolve example.com:443:ORIGIN_IP https://example.com/protected/.
Prevention Tips
- Use a password manager and update saved credentials when passwords change.
- Store API tokens in environment variables, and track their expiry dates.
- Use Application Passwords for integrations instead of your main WordPress password.
- Document every Basic Auth setup: which paths, which password file, who has access.
- Never cache authenticated responses or 401 responses at the CDN level.
- After a server migration, test REST API authentication right away. Header handling often changes between hosts.
When to Contact Support
Contact your host if you see a password prompt you did not set up, if the Authorization header is stripped and you cannot change the server config, or if the 401 started right after a migration or a server-level security change. For third-party APIs, contact the provider with the request ID from the response headers and the time of the failed call.
Frequently Asked Questions
The resource requires authentication, and the request either had no credentials or had credentials the server rejected. The response normally includes a WWW-Authenticate header naming the expected scheme.
401 means you are not authenticated, so valid credentials may fix it. 403 means the server refuses access regardless of who you are, so logging in again will not help.
Often the server strips the Authorization header before it reaches PHP. On Apache, add RewriteRule .* – [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] or CGIPassAuth On, and use an Application Password over HTTPS.
The popup comes from HTTP Basic Auth. Remove or fix the AuthType Basic block in .htaccess or the auth_basic directive in NGINX, or disable password protection in your hosting panel.
Final Thoughts
A 401 Unauthorized error is about missing or rejected credentials. Look at the WWW-Authenticate header first, because it tells you which system is asking for authentication. Then test with curl, check the password file or token, and make sure the Authorization header actually reaches PHP. On WordPress, Application Passwords and correct REST API nonces solve most API-related 401s.