Application Password authentication to WordPress REST API failed silently — returned 401 on all write operations. Root cause: incorrect header format and URL encoding of Application Password spaces.
Impact
WordPress REST API automation script blocked entirely. All write operations (publishing posts, updating metadata) returned 401. No content could be pushed programmatically until the auth header was corrected.
Root Cause
WordPress Application Passwords are displayed with spaces (e.g., 'Kbqw 8P2T QLnS p3Co SlOT SNAb'). The spaces are part of the credential and must be included as-is when Base64 encoding the Authorization header. URL-encoding the spaces as %20 before Base64 encoding corrupts the credential and produces a 401 on every request.
Resolution
Removed URL encoding from the password string before Base64 encoding. The entire 'username:password' string — spaces in password intact — is passed directly to btoa() or base64 equivalent. Verified with curl before updating the automation script.
Prevention Pattern
Test WordPress REST API auth with a simple GET request using curl before writing any automation script. Construct the Authorization header by Base64 encoding the raw credential string — do not URL-encode any part of it.
Recovery
Quick fix (minutes)
Deploy risk
low
Detectable
Immediate — first API call returns 401
Repeat risk
high
Prevention patterns
Ecosystem impact
Related failures
The goal was a Claude Code automation script to update WordPress posts on asquaresolution.com via the REST API — patching post content, updating SEO metadata, and setting tags in bulk. A WordPress Application Password was generated in the dashboard under Users → Profile → Application Passwords.
The first curl test returned 401 Unauthorized. Nothing went through.
curl -X GET https://asquaresolution.com/wp-json/wp/v2/posts \
-H "Authorization: Basic $(echo -n 'cantact:Kbqw%208P2T%20QLnS%20p3Co%20SlOT%20SNAb' | base64)"
Every variation tried — different header formats, different credential strings, double-checking the username — produced the same 401. WordPress was rejecting the credentials silently with no additional error detail in the response body.
WordPress Application Passwords are shown in the dashboard formatted with spaces between character groups: Kbqw 8P2T QLnS p3Co SlOT SNAb. These spaces are not decorators — they are part of the actual password string and must be present when constructing the Authorization header.
The mistake was URL-encoding the spaces to %20 before Base64 encoding. This produces a different Base64 string than WordPress expects, so authentication fails every time.
The correct process:
cantact:Kbqw 8P2T QLnS p3Co SlOT SNAbAuthorization: Basic <base64-result># Correct
curl -X GET https://asquaresolution.com/wp-json/wp/v2/posts \
-H "Authorization: Basic $(echo -n 'cantact:Kbqw 8P2T QLnS p3Co SlOT SNAb' | base64)"
The difference: echo -n 'cantact:Kbqw 8P2T ...' — the password passed raw, spaces included, piped directly to base64. No URL encoding anywhere in the chain.
⚠Application Password spaces are not formatting
WordPress displays Application Passwords with spaces for readability, but the spaces are part of the credential. The REST API expects the Base64 of the raw string with spaces. URL-encoding or removing the spaces produces a different hash and a guaranteed 401.
A second issue compounded the debugging: the initial test was hitting the wrong endpoint format for write operations. WordPress REST API write operations require:
POST /wp-json/wp/v2/posts/{id}Content-Type: application/jsonMissing Content-Type: application/json on a POST causes WordPress to ignore the request body and return a 400 or process the request incorrectly. This was not the root cause of the 401, but it would have caused the next failure in sequence.
| Step | Action | Result |
|---|---|---|
| 1 | Tested endpoint URL with public GET | 200 — endpoint is correct |
| 2 | Added auth header with URL-encoded password | 401 |
| 3 | Checked WordPress user has correct role | OK — Administrator |
| 4 | Re-read Application Password docs | Found spaces-are-literal note |
| 5 | Rebuilt curl command with raw password string | 200 — authenticated |
| 6 | Tested write operation with Content-Type header | 200 — post updated |
| 7 | Updated automation script | Working |
Before writing any WordPress REST API automation:
The 401 from WordPress gives no indication of why it failed. There is no "password format incorrect" message. This makes the spaces issue genuinely easy to miss and easy to repeat — hence the high repeat risk rating.
Fix Confidence
Recovery Complexity
Pattern Family
This failure belongs to a named recurring pattern. Other failures in this family share the same root cause structure — understanding the pattern prevents multiple failure types simultaneously.
Related Failures in Same Pattern
Resolver Playbooks