You generate a WordPress Application Password, plug it into Postman, a mobile app, or a Zapier/Make integration, and the very first request comes back 401 Unauthorized with "rest_not_logged_in" or "Sorry, you are not allowed to do that." The password is correct — you just copied it straight from the WordPress dashboard. So why does WordPress act like it never saw any credentials at all?
Nine times out of ten on shared or cPanel-style hosting, the answer isn't WordPress. It's the web server quietly deleting the Authorization header before PHP ever sees it. Here's how to confirm that, fix it, and avoid the handful of other things that break Application Password auth.
Symptom: correct password, still 401
The pattern usually looks like this:
- You create the app password under Users → Profile → Application Passwords, and WordPress shows the usual four-word password with spaces (e.g.
abcd 1234 efgh 5678). - You send a request to
/wp-json/wp/v2/users/mewith HTTP Basic Auth: username + that password. - Logged-in requests from the browser (using cookies) work fine. Anything authenticating with the app password fails.
- The response is
401, sometimes withrest_not_logged_in, sometimes with a generic "not allowed" message — not a helpful "bad password" error, because WordPress never got a password to check in the first place.
That last point is the tell. If WordPress actually evaluated your credentials and rejected them, you'd get a different error. Silence usually means the header didn't arrive.
Cause 1: Apache/cPanel is stripping the Authorization header
This is the big one, and it trips up almost everyone the first time they try Application Passwords on shared hosting or a stock cPanel VPS.
PHP running as CGI or under suPHP (both common on shared hosting) doesn't automatically expose the Authorization header to your script. Apache's mod_cgi/mod_fcgid layer just... drops it, because it was never designed to pass authentication headers through to CGI processes. WordPress's REST API relies on reading HTTP_AUTHORIZATION (or REDIRECT_HTTP_AUTHORIZATION) from the server environment, and if that variable never gets set, there's nothing to authenticate against — hence the silent 401.
You can confirm this in about 30 seconds with a quick test script.
<?php
// save as auth-test.php in your site root, visit it, then delete it
echo 'HTTP_AUTHORIZATION: ' . ($_SERVER['HTTP_AUTHORIZATION'] ?? 'NOT SET') . "\n";
echo 'REDIRECT_HTTP_AUTHORIZATION: ' . ($_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? 'NOT SET') . "\n";
Hit it with:
curl -u "admin:abcd 1234 efgh 5678" https://yourdomain.com/auth-test.php
If both lines say NOT SET, the header is being dropped before PHP ever runs — confirmed.
The fix: pass the header through in .htaccess
Add this near the top of your WordPress root .htaccess, before the standard WordPress rewrite block:
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [E=HTTP_AUTHORIZATION:%1]
On some cPanel setups you'll need the CGI-specific variant instead (or in addition):
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
Re-run the auth-test.php check. Once HTTP_AUTHORIZATION shows your Basic Auth string instead of NOT SET, the REST API call will start authenticating correctly. Delete the test file when you're done — don't leave it sitting on a live site.
If you're on a SkyServer VPS running PHP-FPM instead of CGI/suPHP, this usually isn't an issue at all, since FPM passes the full header set through by default. It's almost exclusively a CGI/suPHP shared-hosting problem.
Cause 2: the site isn't fully on HTTPS
WordPress disables Application Passwords entirely on non-HTTPS sites unless a filter explicitly overrides it. If your site is still serving admin/API traffic over plain http://, or you've got mixed content where wp-json resolves to an insecure URL, the feature silently won't work — no password you generate will ever authenticate.
Check Tools → Site Health → Info → WordPress Constants or simply confirm https://yourdomain.com/wp-json/ loads without a certificate warning. If AutoSSL isn't active, get that sorted first — Application Passwords isn't the actual bug in that case.
Cause 3: a security plugin is blocking or disabling it
Wordfence, iThemes Security, and similar plugins often ship a toggle to disable Application Passwords or to lock down the REST API for unauthenticated/external clients. Check for settings named something like "Disable Application Passwords," "REST API access," or "XML-RPC and Application Passwords." Firewall rules that block requests without a standard browser User-Agent header (common in WAF configs) will also silently kill API clients like Postman or a mobile app's HTTP library — whitelist the specific endpoint or client if that's the case.
Cause 4: wrong password format
This one's simple but common: Application Passwords are generated with spaces, and WordPress strips those spaces internally when comparing. Some HTTP clients or config files choke if you paste the password with the spaces removed, or double-encode it. Copy it exactly as WordPress shows it, spaces included, and let your HTTP client's Basic Auth field handle the encoding — don't hand-build the Authorization: Basic ... header yourself unless you're base64-encoding username:app password correctly.
Quick reference
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 on every request, no matter the password | Authorization header stripped (CGI/suPHP) | Add RewriteRule/SetEnvIf to .htaccess |
| App Passwords menu missing under user profile | Site not fully on HTTPS, or feature disabled by a plugin/filter | Fix SSL; check security plugin settings |
| 401 only from specific clients (curl works, app doesn't) | Client not sending Basic Auth correctly, or WAF blocking its User-Agent | Fix client auth config; whitelist in firewall |
| Worked before, broke after a plugin update | New plugin restricting REST API or Application Passwords | Deactivate plugins one by one to isolate it |
Prevention
A few habits save you the debugging session next time:
- Test the
auth-test.phpheader check once, right after moving to a new host, before you build anything against the REST API. - Create a separate Application Password per integration (one for Zapier, one for a mobile app, one for a backup script) so you can revoke one without breaking the others.
- Revoke unused app passwords from the same screen you created them on — they don't expire on their own.
- If you manage multiple sites, keep a note of which ones run PHP-FPM vs CGI/suPHP, since that single detail predicts whether you'll hit this header-stripping issue at all.
Frequently Asked Questions
Do I need to enable anything to use Application Passwords?
No — it's built into WordPress core since 5.6 and is on by default on any HTTPS site. If the option is missing from your user profile page, the site almost certainly isn't serving over HTTPS, or a plugin has explicitly disabled it.
Is this the same issue as XML-RPC being blocked?
No. XML-RPC and the REST API are separate systems with separate authentication paths. Blocking XML-RPC for security (a good idea on most sites) has no effect on Application Passwords or REST API auth.
Why does it work in Postman but not in my app's code?
Usually the app's HTTP library isn't sending a proper Authorization: Basic header — check whether it's URL-encoding the credentials, sending them as query params instead, or missing the header entirely. Compare the raw request Postman sends (via its console) against what your code sends.
Can I use Application Passwords with a Nginx-only VPS (no Apache)?
Yes, and Nginx running PHP via FPM generally passes the Authorization header through without any extra configuration — this header-stripping problem is specific to Apache with CGI/suPHP PHP handlers. If you're still seeing it on Nginx, check for a fastcgi_param block that might be filtering headers, or a reverse proxy in front of it dropping them.
Is it safe to leave the .htaccess fix in place permanently?
Yes — that RewriteRule only forwards a header that was already sent by the client; it doesn't weaken security. It's a standard, widely-used snippet for CGI/suPHP environments and causes no side effects for sites that don't use Basic Auth at all.
