WordPress REST API 401/403 Unauthorized – Authentication Guide
WordPress REST API Authentication
Master authentication to fix 401 and 403 errors
If you're building a headless WordPress site or integrating with third-party apps, you've likely encountered the dreaded 401 Unauthorized or 403 Forbidden errors when calling the REST API. These errors are almost always authentication-related — but the fix depends on why WordPress is rejecting your request.
In this comprehensive guide, we'll cover all the common causes of 401/403 errors, explain the various authentication methods available (API keys, OAuth, JWT, Application Passwords, and more), and provide step-by-step debugging techniques. By the end, you'll be able to confidently secure your REST API calls.
1. Understanding 401 vs. 403
Before diving into fixes, it's crucial to differentiate between these two status codes:
- 401 Unauthorized – The request lacks valid authentication credentials. You need to provide a valid token, API key, or user credentials.
- 403 Forbidden – The request is authenticated, but the authenticated user does not have permission to perform the requested action (e.g., reading private posts, creating users).
Both errors indicate authentication issues, but 403 often requires checking user roles and capabilities.
2. Common Causes of 401/403 Errors
- Missing or invalid nonce – For authenticated requests that require a nonce (especially when using cookies).
- No authentication header – You didn't send an
Authorizationheader. - Expired or malformed token – JWTs or OAuth tokens may be invalid.
- Application Password not enabled – For simple password-based auth, you need to enable Application Passwords.
- User role lacks capability – The authenticated user doesn't have the required capability (e.g.,
edit_posts). - REST API disabled – Some plugins or hosts disable the REST API for non-logged-in users.
- Security plugin blocking – Plugins like Wordfence or iThemes Security may block certain requests.
- HTTPS/SSL mismatch – Mixed content or incorrect site URL can cause authentication failures.
3. Authentication Methods for the WordPress REST API
WordPress supports several authentication methods. Choosing the right one depends on your use case (headless, mobile app, external service).
3.1 Application Passwords (Built-in)
Since WordPress 5.6, Application Passwords allow you to generate a password for API access without using your main account password. This is the simplest way to authenticate for basic requests.
// Example: using Application Password in Basic Auth header
$username = 'your_username';
$password = 'your_application_password';
$auth = base64_encode( $username . ':' . $password );
$headers = [ 'Authorization' => 'Basic ' . $auth ];
// In cURL:
curl -X GET https://example.com/wp-json/wp/v2/posts \
-H "Authorization: Basic " . base64_encode("user:app_password")
3.2 JSON Web Tokens (JWT)
JWT is popular for headless setups. You exchange user credentials for a token, then send that token in the Authorization header. You'll need a plugin like JWT Authentication for WP-API.
// Get token
POST /wp-json/jwt-auth/v1/token
Body: { "username": "admin", "password": "pass" }
Response: { "token": "eyJ0eXAi..." }
// Use token in subsequent requests
GET /wp-json/wp/v2/posts
Header: Authorization: Bearer eyJ0eXAi...
3.3 OAuth 2.0
For complex integrations with third-party apps, OAuth 2.0 provides a secure authorization flow. Plugins like OAuth 2.0 Server implement this.
3.4 Cookie Authentication (Nonce)
When you're logged into WordPress admin, cookies are used. For REST API requests from the same site, you need to pass a nonce in the X-WP-Nonce header.
// Get nonce in JavaScript
const nonce = wpApiSettings.nonce;
fetch('/wp-json/wp/v2/posts', {
headers: {
'X-WP-Nonce': nonce
}
});
4. Step-by-Step Debugging 401/403 Errors
4.1 Check the Request Headers
Use browser DevTools or a tool like Postman to inspect exactly what headers you're sending. Ensure the Authorization header is correctly formatted.
4.2 Verify User Permissions
If you're getting 403, check if the user has the required capability. For example, to create a post, you need publish_posts. Use current_user_can() to test.
4.3 Enable REST API Logging
Use plugins like WP REST API Log or custom rest_pre_dispatch hooks to log authentication attempts.
add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) {
error_log( 'REST API request: ' . $request->get_route() . ' - Auth: ' . print_r( $request->get_headers(), true ) );
return $result;
}, 10, 3 );
4.4 Test with a Simple cURL Command
This isolates the issue from your application code.
curl -X GET https://example.com/wp-json/wp/v2/users/me \
-H "Authorization: Basic $(echo -n 'user:app_password' | base64)"
5. Fixing Common Scenarios
Scenario: 401 when using Application Password
Ensure that:
- Application Passwords are enabled (they are by default, but some hosts disable them).
- You're using the correct username and the generated password (not your main password).
- The
Authorizationheader usesBasicscheme. - Your server supports HTTP Basic Auth (sometimes requires .htaccess configuration).
Scenario: 403 when trying to access private posts
The user lacks the read_private_posts capability. Either grant the capability or adjust your request to only query public posts.
6. Security Plugins and REST API Restrictions
Many security plugins (e.g., Wordfence, iThemes Security, Sucuri) block REST API access for unauthenticated users or restrict certain endpoints. Check your plugin settings and whitelist necessary routes.
Also, some hosts disable the REST API for performance reasons. You can test by adding this to your theme's functions.php:
// Force enable REST API if disabled
add_filter( 'rest_enabled', '__return_true' );
add_filter( 'rest_jsonp_enabled', '__return_true' );
7. Advanced: Custom Authentication with Filters
For custom authentication flows (e.g., API keys from a database), you can hook into determine_current_user or rest_authentication_errors.
// Example: API key authentication
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
$api_key = $_SERVER['HTTP_X_API_KEY'] ?? '';
if ( $api_key === 'my-secret-key' ) {
// Set user ID
wp_set_current_user( 1 );
} else {
return new WP_Error( 'rest_forbidden', 'Invalid API key', array( 'status' => 401 ) );
}
return $result;
});
8. Testing with Postman or Insomnia
Use API clients to test your endpoints with different authentication methods. This helps isolate whether the issue is in your code or the server.
- Set Authorization to
Basic Authand enter username/application password. - For JWT, set
Bearer Token. - Check the response headers for
X-WP-Nonceif using cookie auth.
9. Conclusion
Fixing 401 and 403 errors in the WordPress REST API is all about understanding the authentication method you're using and ensuring your requests match the expected format. Start with the simplest method (Application Passwords) and move to more complex ones (JWT, OAuth) as needed.
Remember to check user permissions, security plugin settings, and always test with cURL or Postman before blaming your code. With the techniques covered here, you'll be able to resolve most authentication issues quickly.
0 Comments
thanks for your comments!