Authentication: Securing API Access
Why Authentication?
Read operations (GET) on public content don't require authentication. But to:
- Create, update, or delete content
- Access private/draft posts
- Modify settings
- Access user data
You need to authenticate your requests.
Authentication Methods
| Method | Best For | Security Level |
|---|---|---|
| Application Passwords | Server-to-server, personal scripts | Good |
| JWT Tokens | SPAs, mobile apps | Better |
| OAuth 2.0 | Third-party apps | Best |
| Cookie Auth | Same-domain JavaScript | Built-in |
Application Passwords (WordPress 5.6+)
The simplest method โ built into WordPress core.
Creating an Application Password
- Go to Users โ Profile
- Scroll to Application Passwords
- Enter a name (e.g., "My Script")
- Click Add New Application Password
- Copy the generated password (shown only once!)
Using Application Passwords
# Encode credentials as Base64
echo -n "username:application_password" | base64
# Result: dXNlcm5hbWU6YXBwbGljYXRpb25fcGFzc3dvcmQ=
# Use in requests
curl -X POST https://site.com/wp-json/wp/v2/posts
-H "Authorization: Basic dXNlcm5hbWU6YXBwbGljYXRpb25fcGFzc3dvcmQ="
-H "Content-Type: application/json"
-d '{"title":"New Post","content":"Hello!","status":"publish"}'JavaScript Example
const credentials = btoa('username:xxxx xxxx xxxx xxxx xxxx xxxx');
async function createPost(title, content) {
const response = await fetch('/wp-json/wp/v2/posts', {
method: 'POST',
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
title,
content,
status: 'publish'
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}JWT Authentication
JSON Web Tokens are better for client applications. Install a JWT plugin like JWT Authentication for WP REST API.
Setup
- Install the JWT plugin
- Add to
wp-config.php:
define('JWT_AUTH_SECRET_KEY', 'your-secret-key-here');
define('JWT_AUTH_CORS_ENABLE', true);- Add to
.htaccess:
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1]Getting a Token
async function getToken(username, password) {
const response = await fetch('/wp-json/jwt-auth/v1/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
});
const data = await response.json();
if (data.token) {
return data.token;
}
throw new Error(data.message);
}Using the Token
const token = await getToken('admin', 'password');
// Use token in subsequent requests
const response = await fetch('/wp-json/wp/v2/posts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: 'JWT Authenticated Post',
content: 'Created with JWT!',
status: 'publish'
})
});Token Validation
async function validateToken(token) {
const response = await fetch('/wp-json/jwt-auth/v1/token/validate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
}
});
return response.ok;
}Cookie Authentication (Same Domain)
For JavaScript running on WordPress itself, use the built-in nonce:
// Enqueue script with nonce
wp_enqueue_script('my-api-script', 'path/to/script.js', ['wp-api-fetch'], '1.0', true);
wp_localize_script('my-api-script', 'myApiSettings', [
'nonce' => wp_create_nonce('wp_rest'),
'root' => esc_url_raw(rest_url())
]);// In your JavaScript
async function createPost(title, content) {
const response = await fetch(`${myApiSettings.root}wp/v2/posts`, {
method: 'POST',
headers: {
'X-WP-Nonce': myApiSettings.nonce,
'Content-Type': 'application/json'
},
body: JSON.stringify({ title, content, status: 'publish' })
});
return response.json();
}OAuth 2.0 (For Third-Party Apps)
For apps that need to authenticate multiple users, use OAuth. Install WP OAuth Server or similar.
// OAuth 2.0 flow (simplified)
const clientId = 'your_client_id';
const redirectUri = 'https://yourapp.com/callback';
// 1. Redirect user to authorize
const authUrl = `https://site.com/oauth/authorize?
client_id=${clientId}&
redirect_uri=${encodeURIComponent(redirectUri)}&
response_type=code`;
window.location = authUrl;
// 2. Exchange code for token (on your server)
async function exchangeCodeForToken(code) {
const response = await fetch('https://site.com/oauth/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
client_id: clientId,
client_secret: 'your_secret',
redirect_uri: redirectUri
})
});
return response.json();
}Handling Authentication Errors
async function apiRequest(endpoint, options = {}) {
const response = await fetch(endpoint, {
...options,
headers: {
'Authorization': `Bearer ${getStoredToken()}`,
'Content-Type': 'application/json',
...options.headers
}
});
if (response.status === 401) {
// Token expired or invalid
clearStoredToken();
redirectToLogin();
return;
}
if (response.status === 403) {
throw new Error('You do not have permission to perform this action');
}
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'API request failed');
}
return response.json();
}Next Steps
In the next lesson, we'll perform write operations โ creating, updating, and deleting posts, pages, and other content via the API.