Voxfor - All rights reserved - 2013-2025
We Accepted





The WordPress REST API is a powerful tool for developers to interact programmatically with WordPress sites. While it supports several built-in authentication methods (e.g., cookies, OAuth, and application passwords), there are scenarios where a custom solution like JSON Web Tokens (JWT) is preferable. WordPress REST API JWT Authentication offer stateless authentication, scalability, and compatibility with modern decoupled architectures. However, implementing a custom authentication method requires careful planning to avoid conflicts with existing authentication flows.
This guide provides an orderly process for integrating JWT token authentication into the WordPress REST API while preserving compatibility with core authentication systems.
JWT tokens are compact, URL-safe tokens that securely transmit information between parties. They are ideal for REST API authentication because:
Key Challenges:
To handle JWT encoding/decoding, use a trusted library like firebase/php-jwt. Install it via Composer:
composer require firebase/php-jwtย
If Composer isn’t available, download the library manually and include it in your plugin:
// Include the JWT libraryย ย
require_once plugin_dir_path(__FILE__) . 'vendor/autoload.php';ย ย
use Firebase\JWT\JWT;ย ย
use Firebase\JWT\Key;
Create a custom REST API endpoint where users can exchange their credentials for a JWT token.
Add the following to your plugin or theme’s functions.php:
add_action('rest_api_init', 'register_jwt_auth_endpoints');ย ย
function register_jwt_auth_endpoints() {ย ย
ย ย register_rest_route('jwt-auth/v1', '/token', array(ย ย
ย ย ย ย 'methods'ย => 'POST',ย ย
ย ย ย ย 'callback' => 'issue_jwt_token',ย ย
ย ย ));ย ย
}
Validate user credentials and issue a token:
function issue_jwt_token(WP_REST_Request $request) {ย ย
ย ย $username = $request->get_param('username');ย ย
ย ย $password = $request->get_param('password');ย ย
ย ย // Authenticate the userย ย
ย ย $user = wp_authenticate($username, $password);ย ย
ย ย if (is_wp_error($user)) {ย ย
ย ย ย ย return new WP_REST_Response(ย ย
ย ย ย ย ย ย array('error' => 'Invalid credentials'),ย ย
ย ย ย ย ย ย 401ย ย
ย ย ย ย );ย ย
ย ย }ย ย
ย ย // Generate JWT payloadย ย
ย ย $issued_at = time();ย ย
ย ย $expiration = $issued_at + (DAY_IN_SECONDS * 1); // 1-day lifespanย ย
ย ย $payload = array(ย ย
ย ย ย ย 'iss' => get_bloginfo('url'),ย ย
ย ย ย ย 'iat' => $issued_at,ย ย
ย ย ย ย 'exp' => $expiration,ย ย
ย ย ย ย 'nbf' => $issued_at,ย ย
ย ย ย ย 'data' => array(ย ย
ย ย ย ย ย ย 'user_id' => $user->ID,ย ย
ย ย ย ย )ย ย
ย ย );ย ย
ย ย // Sign the token with a secret keyย ย
ย ย $secret_key = defined('JWT_AUTH_SECRET_KEY') ? JWT_AUTH_SECRET_KEY : 'your-strong-secret-here';ย ย
ย ย $token = JWT::encode($payload, $secret_key, 'HS256');ย ย
ย ย return new WP_REST_Response(array(ย ย
ย ย ย ย 'token' => $token,ย ย
ย ย ย ย 'user_id' => $user->ID,ย ย
ย ย ย ย 'expires_in' => $expirationย ย
ย ย ), 200);ย ย
}
Explanation:
Intercept incoming API requests, validate the JWT token, and authenticate the user.
add_filter('rest_pre_dispatch', 'validate_jwt_token', 10, 3);ย ย
function validate_jwt_token($result, $server, $request) {ย ย
ย ย // Skip validation if the token is absentย ย
ย ย $auth_header = $request->get_header('Authorization');ย ย
ย ย if (!$auth_header || !preg_match('/Bearer\s(\S+)/', $auth_header, $matches)) {ย ย
ย ย ย ย return $result;ย ย
ย ย }ย ย
ย ย $token = $matches[1];ย ย
ย ย $secret_key = defined('JWT_AUTH_SECRET_KEY') ? JWT_AUTH_SECRET_KEY : 'your-strong-secret-here';ย ย
ย ย try {ย ย
ย ย ย ย // Decode and validate the tokenย ย
ย ย ย ย $payload = JWT::decode($token, new Key($secret_key, 'HS256'));ย ย
ย ย ย ย $user_id = $payload->data->user_id;ย ย
ย ย ย ย // Set the current userย ย
ย ย ย ย wp_set_current_user($user_id);ย ย
ย ย } catch (Exception $e) {ย ย
ย ย ย ย return new WP_Error(ย ย
ย ย ย ย ย ย 'jwt_auth_invalid_token',ย ย
ย ย ย ย ย ย 'Invalid or expired token',ย ย
ย ย ย ย ย ย array('status' => 401)ย ย
ย ย ย ย );ย ย
ย ย }ย ย
ย ย return $result;ย ย
}
Key Points:
To prevent conflicts with WordPress default authentication systems:
// php Code
// In wp-config.phpย
define('JWT_AUTH_SECRET_KEY', 'your-random-256-bit-secret');ย
Extend the token system to allow renewal without re-authentication.
// php code
register_rest_route('jwt-auth/v1', '/refresh', array(ย ย
ย ย 'methods'ย => 'POST',ย ย
ย ย 'callback' => 'refresh_jwt_token',ย ย
));ย ย
function refresh_jwt_token(WP_REST_Request $request) {ย ย
ย ย $old_token = $request->get_param('refresh_token');ย ย
ย ย try {ย ย
ย ย ย ย $secret_key = defined('JWT_AUTH_SECRET_KEY') ? JWT_AUTH_SECRET_KEY : 'your-strong-secret-here';ย ย
ย ย ย ย $payload = JWT::decode($old_token, new Key($secret_key, 'HS256'));ย ย
ย ย ย // Validate the refresh token (e.g., check a allowlist)ย ย
ย ย ย ย if ($payload->type !== 'refresh') {ย ย
ย ย ย ย ย ย throw new Exception('Invalid token type');ย ย
ย ย ย ย }ย ย
ย ย ย ย // Issue a new access tokenย ย
ย ย ย ย $user_id = $payload->data->user_id;ย ย
ย ย ย ย $user = get_user_by('ID', $user_id);ย ย
ย ย ย ย $issued_at = time();ย ย
ย ย ย ย $expiration = $issued_at + (DAY_IN_SECONDS * 1);ย ย
ย ย ย ย $payload = array(ย ย
ย ย ย ย ย ย 'iss' => get_bloginfo('url'),ย ย
ย ย ย ย ย ย 'iat' => $issued_at,ย ย
ย ย ย ย ย ย 'exp' => $expiration,ย ย
ย ย ย ย ย ย 'data' => array('user_id' => $user_id)ย ย
ย ย ย ย );ย ย
ย ย ย ย $new_token = JWT::encode($payload, $secret_key, 'HS256');ย ย
ย ย ย ย return new WP_REST_Response(array(ย ย
ย ย ย ย ย ย 'token' => $new_token,ย ย
ย ย ย ย ย ย 'expires_in' => $expirationย ย
ย ย ย ย ), 200);ย ย
ย ย } catch (Exception $e) {ย ย
ย ย ย ย return new WP_REST_Response(array('error' => 'Invalid refresh token'), 401);ย ย
ย ย }ย ย
}
Use Postman or Curl to test the endpoints:
// bash code
curl -X POST https://yoursite.com/wp-json/jwt-auth/v1/token \ย ย
ย ย -H "Content-Type: application/json" \ย ย
ย ย -d '{"username":"admin","password":"your_password"}'
// bash code
curl https://yoursite.com/wp-json/wp/v2/users/me \ย ย
ย ย -H "Authorization: Bearer YOUR_JWT_TOKEN"
// bash code
curl -X POST https://yoursite.com/wp-json/jwt-auth/v1/refresh \ย ย
ย ย -H "Content-Type: application/json" \ย ย
ย ย -d '{"refresh_token":"YOUR_REFRESH_TOKEN"}'ย
Implementing a custom JWT authentication method for the WordPress REST API enhances security and flexibility, especially for modern applications that require stateless authentication. By following the steps outlined in this guide, developers can establish a powerful authentication system that functions alongside existing methods, ensuring a seamless user experience.
Remember to adhere to security best practices, regularly audit your implementation, and keep your JWT library updated to mitigate vulnerabilities. With JWT tokens, you can empower your WordPress applications to interact securely and efficiently with various clients, paving the way for innovative solutions in the WordPress ecosystem.
Hassan Tahir wrote this article, drawing on his experience to clarify WordPress concepts and enhance developer understanding. Through his work, he aims to help both beginners and professionals refine their skills and tackle WordPress projects with greater confidence.