Securing WordPress REST API: Complete Protection Guide
Protect your WordPress REST API endpoints with authentication, rate limiting, and access control measures.
The WordPress REST API exposes site functionality to external applications. Without proper security, it can leak data and provide attack vectors.
REST API Security Concerns
Default Exposures
- User enumeration via /wp-json/wp/v2/users
- Content access without authentication
- Site information disclosure
- Plugin/theme information leaks
Authentication Methods
Cookie Authentication
// Built-in for logged-in users
// Requires nonce for write operations
wp_localize_script('my-script', 'wpApiSettings', array(
'root' => esc_url_raw(rest_url()),
'nonce' => wp_create_nonce('wp_rest')
));
// JavaScript fetch with nonce
fetch(wpApiSettings.root + 'wp/v2/posts', {
headers: {
'X-WP-Nonce': wpApiSettings.nonce
}
});
Application Passwords
// WordPress 5.6+ built-in feature
// Create in User Profile
// Use with Basic Auth header
Authorization: Basic base64(username:application_password)
// PHP example
$auth = base64_encode('username:xxxx xxxx xxxx xxxx xxxx xxxx');
$response = wp_remote_get(rest_url('wp/v2/posts'), array(
'headers' => array(
'Authorization' => 'Basic ' . $auth
)
));
Restrict User Endpoint
Hide User Information
// Remove users endpoint
add_filter('rest_endpoints', 'wpfs_remove_user_endpoint');
function wpfs_remove_user_endpoint($endpoints) {
if (isset($endpoints['/wp/v2/users'])) {
unset($endpoints['/wp/v2/users']);
}
if (isset($endpoints['/wp/v2/users/(?P[\d]+)'])) {
unset($endpoints['/wp/v2/users/(?P[\d]+)']);
}
return $endpoints;
}
// Or require authentication for users endpoint
add_filter('rest_authentication_errors', 'wpfs_restrict_users_api');
function wpfs_restrict_users_api($result) {
if (strpos($_SERVER['REQUEST_URI'], '/wp/v2/users') !== false) {
if (!is_user_logged_in()) {
return new WP_Error(
'rest_forbidden',
'Authentication required',
array('status' => 401)
);
}
}
return $result;
}
Rate Limiting
Implement API Rate Limits
add_filter('rest_pre_dispatch', 'wpfs_api_rate_limit', 10, 3);
function wpfs_api_rate_limit($result, $server, $request) {
$ip = $_SERVER['REMOTE_ADDR'];
$transient_key = 'api_rate_' . md5($ip);
$requests = get_transient($transient_key) ?: 0;
$limit = 100; // requests per minute
if ($requests >= $limit) {
return new WP_Error(
'rate_limit_exceeded',
'Too many requests',
array('status' => 429)
);
}
set_transient($transient_key, $requests + 1, 60);
return $result;
}
Custom Endpoint Security
Secure Custom Endpoints
// Register secure endpoint
register_rest_route('wpfs/v1', '/secure-data', array(
'methods' => 'GET',
'callback' => 'wpfs_secure_data_callback',
'permission_callback' => function() {
return current_user_can('edit_posts');
}
));
function wpfs_secure_data_callback($request) {
// Additional validation
$param = sanitize_text_field($request->get_param('id'));
if (empty($param)) {
return new WP_Error(
'invalid_param',
'ID required',
array('status' => 400)
);
}
// Return data
return new WP_REST_Response(array('data' => $result), 200);
}
Input Validation
Validate and Sanitize
register_rest_route('wpfs/v1', '/submit', array(
'methods' => 'POST',
'callback' => 'wpfs_handle_submission',
'permission_callback' => '__return_true',
'args' => array(
'email' => array(
'required' => true,
'validate_callback' => function($param) {
return is_email($param);
},
'sanitize_callback' => 'sanitize_email'
),
'message' => array(
'required' => true,
'sanitize_callback' => 'sanitize_textarea_field'
)
)
));
Disable REST API (If Not Needed)
Complete Disable
// Disable for non-logged-in users
add_filter('rest_authentication_errors', 'wpfs_disable_rest_api');
function wpfs_disable_rest_api($result) {
if (!is_user_logged_in()) {
return new WP_Error(
'rest_disabled',
'REST API disabled',
array('status' => 403)
);
}
return $result;
}
CORS Configuration
Restrict Origins
add_action('rest_api_init', 'wpfs_cors_headers');
function wpfs_cors_headers() {
$allowed_origins = array(
'https://yoursite.com',
'https://app.yoursite.com'
);
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowed_origins)) {
header('Access-Control-Allow-Origin: ' . $origin);
}
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Content-Type');
}
Logging API Requests
add_action('rest_api_init', 'wpfs_log_api_requests');
function wpfs_log_api_requests() {
$request_uri = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];
$ip = $_SERVER['REMOTE_ADDR'];
error_log(sprintf(
'REST API: %s %s from %s',
$method,
$request_uri,
$ip
));
}
Conclusion
REST API security requires authentication, rate limiting, and careful endpoint exposure. Disable or restrict endpoints you don't need, validate all inputs, and monitor API usage.
Written by Sarah Chen
WP Folder Shield Team