Application Passwords, header format, auth testing, and common failure modes.
Every WordPress REST API automation starts with authentication. Get it wrong and you're locked out, doing read-only operations, or — worse — committing credentials to your repo. Get it right and you have a reliable, revocable, auditable connection to your WordPress instance.
⬡ What you'll build
Option 1: Application Passwords (use this)
Built into WordPress 5.6+. User-specific. Named and revocable individually. Works with Basic Auth header. No plugin required. This is the correct choice for automation.
Option 2: Basic Auth with real password
Uses your actual WordPress password. Works, but: if exposed, the impact is your entire account. No granular revocation. Bad practice for automation — don't use it.
Option 3: JWT Authentication
Requires a third-party plugin (JWT Authentication for WP REST API, etc.). More complex, token expiry to manage, plugin maintenance overhead. Not worth it unless you have specific requirements that Application Passwords don't meet.
Use Application Passwords. Always.
In WordPress Admin:
Claude Code Automation - ProductionThe generated password looks like: abcd efgh ijkl mnop qrst uvwx (24 characters with spaces)
The header format for Application Passwords uses HTTP Basic Auth:
import base64
username = "your_wordpress_username"
app_password = "abcd efgh ijkl mnop qrst uvwx" # with spaces, as generated
# Remove spaces from the password (WordPress accepts both, but convention removes them)
credentials = f"{username}:{app_password.replace(' ', '')}"
encoded = base64.b64encode(credentials.encode()).decode()
headers = {
"Authorization": f"Basic {encoded}",
"Content-Type": "application/json"
}const username = "your_wordpress_username"
const appPassword = "abcd efgh ijkl mnop qrst uvwx"
const credentials = Buffer.from(
`${username}:${appPassword.replace(/ /g, '')}`
).toString('base64')
const headers = {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/json'
}Always verify your credentials work before writing a single line of automation logic:
A successful response returns your user data. If you see an error, fix auth before proceeding.
Quick Python auth test:
import requests
import base64
USERNAME = "your_username"
APP_PASSWORD = "xxxx xxxx xxxx xxxx xxxx xxxx"
credentials = base64.b64encode(
f"{USERNAME}:{APP_PASSWORD.replace(' ', '')}".encode()
).decode()
response = requests.get(
"https://yoursite.com/wp-json/wp/v2/users/me",
headers={"Authorization": f"Basic {credentials}"}
)
if response.status_code == 200:
user = response.json()
print(f"✓ Auth successful. Logged in as: {user['name']} (ID: {user['id']})")
print(f" Roles: {user.get('roles', [])}")
else:
print(f"✗ Auth failed. Status: {response.status_code}")
print(f" Response: {response.text[:200]}")401 Unauthorized
The credentials are wrong. Check:
-u flag first (it handles encoding for you)403 Forbidden
Authenticated, but the user doesn't have the capability for this operation. Check:
edit_posts capability is required for most write operationsApplication Passwords not available
Some hosting environments disable Application Passwords:
Failure Pattern — Credentials in source code
✕ Before (broken pattern)
# automation.py USERNAME = "admin" APP_PASSWORD = "abcd efgh ijkl mnop" response = requests.get(url, auth=(USERNAME, APP_PASSWORD))
✓ After (production pattern)
# automation.py — credentials from environment import os USERNAME = os.environ["WP_USERNAME"] APP_PASSWORD = os.environ["WP_APP_PASSWORD"] # .env file (never committed to git) # WP_USERNAME=admin # WP_APP_PASSWORD=abcd efgh ijkl mnop # .gitignore # .env
Lesson: Application Passwords are revocable, but only if you notice they were exposed. Never commit credentials to source control — use environment variables and .env files.
Auth is correctly set up when: