{"id":267231,"date":"2026-02-08T10:59:29","date_gmt":"2026-02-08T10:59:29","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/jwt-auth-api\/"},"modified":"2026-02-08T10:59:15","modified_gmt":"2026-02-08T10:59:15","slug":"headlesskey-jwt-auth","status":"publish","type":"plugin","link":"https:\/\/dv.wordpress.org\/plugins\/headlesskey-jwt-auth\/","author":23218544,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"1.0.0","stable_tag":"1.0.0","tested":"6.9.4","requires":"6.0","requires_php":"8.0","requires_plugins":null,"header_name":"HeadlessKey \u2013 JWT Auth","header_author":"Hidayat Mahetar","header_description":"Secure your Headless WordPress with JWT Authentication. Includes Registration, SSO, RBAC, Password Reset, and Brute Force Protection.","assets_banners_color":"767d93","last_updated":"2026-02-08 10:59:15","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/profiles.wordpress.org\/hidayatsafewp\/","rating":5,"author_block_rating":0,"active_installs":0,"downloads":199,"num_ratings":1,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"hidayatsafewp","date":"2026-02-08 10:59:15"}},"upgrade_notice":{"1.0.0":"<p>Initial release. Secure your Headless WordPress with JWT today!<\/p>"},"ratings":{"1":0,"2":0,"3":0,"4":0,"5":1},"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3456339,"resolution":"128x128","location":"assets","locale":""},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3456339,"resolution":"256x256","location":"assets","locale":""},"icon.svg":{"filename":"icon.svg","revision":3456339,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3456339,"resolution":"1544x500","location":"assets","locale":""},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3456339,"resolution":"772x250","location":"assets","locale":""}},"assets_blueprints":{},"all_blocks":{"headlesskey\/demo-block":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"headlesskey\/demo-block","version":"0.1.0","title":"Demo Block","category":"widgets","icon":"smiley","description":"Demo block scaffolded with HeadlessKey.","supports":{"color":{"text":true,"background":true,"link":true}},"attributes":{"selectedUser":{"type":"string"},"user":{"type":"object"}},"textdomain":"headlesskey-jwt-auth","editorScript":"file:.\/index.js","editorStyle":"file:.\/index.css","style":"file:.\/style-index.css"}},"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3456339,"resolution":"1","location":"assets","locale":""},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3456339,"resolution":"2","location":"assets","locale":""},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3456339,"resolution":"3","location":"assets","locale":""}},"screenshots":{"1":"General Settings - Configure Token Expiration and Security Policy.","2":"Algorithms - Choose between HS256, RS256, and ES256.","3":"Logs - View recent authentication activity."},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[710,141196,38851,23853,600],"plugin_category":[38,54],"plugin_contributors":[241285],"plugin_business_model":[],"class_list":["post-267231","plugin","type-plugin","status-publish","hentry","plugin_tags-authentication","plugin_tags-headless","plugin_tags-jwt","plugin_tags-rest-api","plugin_tags-security","plugin_category-authentication","plugin_category-security-and-spam-protection","plugin_contributors-hidayatsafewp","plugin_committers-hidayatsafewp"],"banners":{"banner":"https:\/\/ps.w.org\/headlesskey-jwt-auth\/assets\/banner-772x250.png?rev=3456339","banner_2x":"https:\/\/ps.w.org\/headlesskey-jwt-auth\/assets\/banner-1544x500.png?rev=3456339","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/headlesskey-jwt-auth\/assets\/icon.svg?rev=3456339","icon":"https:\/\/ps.w.org\/headlesskey-jwt-auth\/assets\/icon.svg?rev=3456339","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/headlesskey-jwt-auth\/assets\/screenshot-1.png?rev=3456339","caption":"General Settings - Configure Token Expiration and Security Policy."},{"src":"https:\/\/ps.w.org\/headlesskey-jwt-auth\/assets\/screenshot-2.png?rev=3456339","caption":"Algorithms - Choose between HS256, RS256, and ES256."},{"src":"https:\/\/ps.w.org\/headlesskey-jwt-auth\/assets\/screenshot-3.png?rev=3456339","caption":"Logs - View recent authentication activity."}],"raw_content":"<!--section=description-->\n<p><strong>HeadlessKey \u2013 JWT Auth<\/strong> extends the REST API to provide a robust and secure authentication system using JSON Web Tokens (JWT). Designed for Headless WordPress, it enables seamless user authentication, registration, and session management via standard REST endpoints.<\/p>\n\n<h3>Key Features<\/h3>\n\n<ul>\n<li><strong>Standard JWT Authentication<\/strong>: Secure user authentication using industry-standard RFC 7519 tokens.<\/li>\n<li><strong>Multiple Algorithms<\/strong>: Support for <code>HS256<\/code>, <code>RS256<\/code>, and <code>ES256<\/code> signing algorithms.<\/li>\n<li><strong>Comprehensive Endpoints<\/strong>: Ready-to-use endpoints for Login, Register, Token Refresh, and Password Management.<\/li>\n<li><strong>Single Sign-On (SSO)<\/strong>: Connect multiple sites with a secure, headers-based SSO exchange mechanism.<\/li>\n<li><strong>Role-Based Access Control (RBAC)<\/strong>: Configure public or authenticated access for every endpoint.<\/li>\n<li><strong>Brute Force Protection<\/strong>: Protects against attacks by locking users\/IPs after failed attempts.<\/li>\n<li><strong>Activity Logs<\/strong>: Detailed audit trail of all authentication events, including IP and device data.<\/li>\n<li><strong>Security Webhooks<\/strong>: Real-time JSON events sent to your external services for monitoring key actions.<\/li>\n<li><strong>Device Limits<\/strong>: Restrict the number of active devices\/sessions per user.<\/li>\n<li><strong>Developer Friendly<\/strong>: Extensive hooks and filters for deep customization.<\/li>\n<\/ul>\n\n<h3>Configuration<\/h3>\n\n<h3>Secret Key<\/h3>\n\n<p>The plugin uses a secret key to sign tokens. By default, a secure random key is generated. For better security and consistency across environments, define your key in <code>wp-config.php<\/code>:<\/p>\n\n<pre><code>define('headlesskey_SECRET_KEY', 'your-long-random-secure-string');\n<\/code><\/pre>\n\n<p>You can generate a strong salt here: <a href=\"https:\/\/api.wordpress.org\/secret-key\/1.1\/salt\/\">WordPress Salt Generator<\/a><\/p>\n\n<h3>CORS Support<\/h3>\n\n<p>Cross-Origin Resource Sharing (CORS) is enabled by default to allow frontend applications to connect. To disable or customize it via constant:<\/p>\n\n<pre><code>define('headlesskey_CORS', true); \/\/ or false to disable\n<\/code><\/pre>\n\n<h3>REST API Namespace<\/h3>\n\n<p>By default, endpoints are under <code>wp-json\/wpauthapi\/v1<\/code>. You can customize this namespace:<\/p>\n\n<pre><code>define('headlesskey_REST_NAMESPACE', 'my-custom-auth');\ndefine('headlesskey_REST_VERSION', 'v2');&lt;h3&gt;Endpoints&lt;\/h3&gt;\n<\/code><\/pre>\n\n<p>The plugin adds the following endpoints under the <code>\/wp-json\/headlesskey\/v1<\/code> namespace:<\/p>\n\n\n\n\n  Endpoint\n  HTTP Verb\n  Description\n\n\n\n\n  <code>\/token<\/code>\n  POST\n  <strong>Login<\/strong>: Exchange username\/password for a JWT.\n\n\n  <code>\/token\/validate<\/code>\n  POST\n  <strong>Validate<\/strong>: Check if a token validity.\n\n\n  <code>\/token\/refresh<\/code>\n  POST\n  <strong>Refresh<\/strong>: Exchange a valid token for a new one (rotation).\n\n\n  <code>\/token\/revoke<\/code>\n  POST\n  <strong>Logout<\/strong>: Invalidate a specific token.\n\n\n  <code>\/register<\/code>\n  POST\n  <strong>Register<\/strong>: Create a new user account.\n\n\n  <code>\/login<\/code>\n  POST\n  <strong>Profile<\/strong>: Login and get full user profile data in one request.\n\n\n  <code>\/forgot-password<\/code>\n  POST\n  <strong>Recover<\/strong>: Request a password reset via Link or OTP.\n\n\n  <code>\/reset-password<\/code>\n  POST\n  <strong>Reset<\/strong>: Set a new password using a token or OTP.\n\n\n  <code>\/change-password<\/code>\n  POST\n  <strong>Update<\/strong>: Change password for authenticated user.\n\n\n  <code>\/sso\/exchange<\/code>\n  POST\n  <strong>SSO<\/strong>: Exchange a remote site token for a local session.\n\n\n\n\n<h3>1. Login (Generate Token)<\/h3>\n\n<p><strong>Endpoint:<\/strong> <code>POST \/wp-json\/headlesskey\/v1\/token<\/code>\n<strong>Description:<\/strong> Authenticate a user and generate a JWT token.<\/p>\n\n<p><strong>Request:<\/strong>\n    <code>json\n{\n  \"username\": \"admin\",\n  \"password\": \"secret-password\"\n}<\/code><\/p>\n\n<p><strong>Response:<\/strong>\n    <code>json\n{\n  \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...\",\n  \"expiration\": \"2023-10-27T10:00:00+00:00\",\n  \"expires_in\": 3600,\n  \"user\": {\n    \"ID\": 1,\n    \"user_login\": \"admin\",\n    \"user_email\": \"admin@example.com\",\n    \"display_name\": \"Administrator\",\n    \"roles\": [\"administrator\"]\n  },\n  \"refreshable\": true,\n  \"jti\": \"545086b9-450f-488b-a70d-3047d14d1101\"\n}<\/code><\/p>\n\n<h3>2. Validate Token<\/h3>\n\n<p><strong>Endpoint:<\/strong> <code>POST \/wp-json\/headlesskey\/v1\/token\/validate<\/code>\n<strong>Description:<\/strong> Validate if an existing token is valid.<\/p>\n\n<p><strong>Request:<\/strong>\n    <code>json\n{\n  \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...\"\n}<\/code><\/p>\n\n<p><strong>Response:<\/strong>\n    <code>json\n{\n  \"valid\": true,\n  \"data\": {\n    \"iss\": \"https:\/\/example.com\",\n    \"iat\": 1698393600,\n    \"exp\": 1698397200,\n    \"data\": {\n      \"ID\": 1,\n      \"user_login\": \"admin\"\n    }\n  }\n}<\/code><\/p>\n\n<h3>3. Refresh Token<\/h3>\n\n<p><strong>Endpoint:<\/strong> <code>POST \/wp-json\/headlesskey\/v1\/token\/refresh<\/code>\n<strong>Description:<\/strong> Rotate an expiring token for a fresh one.<\/p>\n\n<p><strong>Request:<\/strong>\n    <code>json\n{\n  \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...\"\n}<\/code><\/p>\n\n<p><strong>Response:<\/strong>\n    <code>json\n{\n  \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.new...\",\n  \"expiration\": \"2023-10-27T11:00:00+00:00\",\n  \"user\": {\n    \"ID\": 1,\n    \"user_login\": \"admin\"\n  },\n  \"jti\": \"new-uuid-v4\"\n}<\/code><\/p>\n\n<h3>4. Revoke Token (Logout)<\/h3>\n\n<p><strong>Endpoint:<\/strong> <code>POST \/wp-json\/headlesskey\/v1\/token\/revoke<\/code>\n<strong>Description:<\/strong> Invalidate a token immediately.<\/p>\n\n<p><strong>Request:<\/strong>\n    <code>json\n{\n  \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...\"\n}<\/code><\/p>\n\n<p><strong>Response:<\/strong>\n    <code>json\n{\n  \"message\": \"Token revoked successfully.\"\n}<\/code><\/p>\n\n<h3>5. Register User<\/h3>\n\n<p><strong>Endpoint:<\/strong> <code>POST \/wp-json\/headlesskey\/v1\/register<\/code>\n<strong>Description:<\/strong> Create a new user account.<\/p>\n\n<p><strong>Request:<\/strong>\n    <code>json\n{\n  \"username\": \"johndoe\",\n  \"email\": \"john@example.com\",\n  \"password\": \"secure-password\",\n  \"name\": \"John Doe\"\n}<\/code><\/p>\n\n<p><strong>Response:<\/strong>\n    <code>json\n{\n  \"user_id\": 45,\n  \"user\": {\n    \"ID\": 45,\n    \"user_login\": \"johndoe\",\n    \"user_email\": \"john@example.com\",\n    \"display_name\": \"John Doe\",\n    \"roles\": [\"subscriber\"]\n  },\n  \"token_response\": {\n    \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOi...\",\n    \"expiration\": \"2023-10-27T10:00:00+00:00\"\n  }\n}<\/code><\/p>\n\n<h3>6. User Profile (Login Extended)<\/h3>\n\n<p><strong>Endpoint:<\/strong> <code>POST \/wp-json\/headlesskey\/v1\/login<\/code>\n<strong>Description:<\/strong> Alternative login endpoint that returns cleaner profile structure.<\/p>\n\n<p><strong>Request:<\/strong>\n    <code>json\n{\n  \"username\": \"admin\",\n  \"password\": \"secret-password\"\n}<\/code><\/p>\n\n<p><strong>Response:<\/strong>\n    <code>json\n{\n  \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...\",\n  \"expiration\": \"2023-10-27T10:00:00+00:00\",\n  \"user\": {\n    \"ID\": 1,\n    \"user_login\": \"admin\",\n    \"user_email\": \"admin@example.com\",\n    \"display_name\": \"Administrator\",\n    \"roles\": [\"administrator\"]\n  }\n}<\/code><\/p>\n\n<h3>7. Forgot Password<\/h3>\n\n<p><strong>Endpoint:<\/strong> <code>POST \/wp-json\/headlesskey\/v1\/forgot-password<\/code>\n<strong>Description:<\/strong> Initiate password recovery. Note: <code>delivery<\/code> can be <code>link<\/code> or <code>otp<\/code>.<\/p>\n\n<p><strong>Request:<\/strong>\n    <code>json\n{\n  \"login\": \"admin@example.com\",\n  \"delivery\": \"link\"\n}<\/code><\/p>\n\n<p><strong>Response:<\/strong>\n    <code>json\n{\n  \"message\": \"Password reset email sent.\"\n}<\/code><\/p>\n\n<h3>8. Reset Password<\/h3>\n\n<p><strong>Endpoint:<\/strong> <code>POST \/wp-json\/headlesskey\/v1\/reset-password<\/code>\n<strong>Description:<\/strong> Reset password using the token sent via email or OTP.<\/p>\n\n<p><strong>Request (Link method):<\/strong>\n    <code>json\n{\n  \"login\": \"admin@example.com\",\n  \"password\": \"new-secure-password\",\n  \"token\": \"generated-reset-key\"\n}<\/code><\/p>\n\n<p><strong>Response:<\/strong>\n    <code>json\n{\n  \"message\": \"Password updated successfully.\"\n}<\/code><\/p>\n\n<h3>9. Change Password<\/h3>\n\n<p><strong>Endpoint:<\/strong> <code>POST \/wp-json\/headlesskey\/v1\/change-password<\/code>\n<strong>Description:<\/strong> Change password for currently authenticated user. Requires <code>Authorization<\/code> header.<\/p>\n\n<p><strong>Headers:<\/strong>\n    Authorization: Bearer <\/p>\n\n<p><strong>Request:<\/strong>\n    <code>json\n{\n  \"current_password\": \"old-password\",\n  \"new_password\": \"new-secure-password\"\n}<\/code><\/p>\n\n<p><strong>Response:<\/strong>\n    <code>json\n{\n  \"message\": \"Password changed successfully. Please login again.\"\n}<\/code><\/p>\n\n<h3>10. SSO Token Exchange<\/h3>\n\n<p><strong>Endpoint:<\/strong> <code>POST \/wp-json\/headlesskey\/v1\/sso\/exchange<\/code>\n<strong>Description:<\/strong> Securely exchange a token from a connected remote site for a local authentication session. This powers the distributed Single Sign-On network.<\/p>\n\n<p><strong>Request:<\/strong>\n    <code>json\n{\n  \"site_key\": \"remote-site-id\",\n  \"token\": \"remote-jwt-token\",\n  \"signature\": \"hmac-sha256-signature\"\n}<\/code><\/p>\n\n<p><strong>Response:<\/strong>\nReturns a standard <strong>Login<\/strong> response (Token + User Data) if the signature is valid.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"how%20do%20i%20generate%20a%20jwt%20secret%3F\"><h3>How do I generate a JWT Secret?<\/h3><\/dt>\n<dd><p>The plugin automatically generates a strong secret key upon activation. You can find it in the plugin settings. For better security, you can define <code>headlesskey_SECRET_KEY<\/code> in your <code>wp-config.php<\/code> file.<\/p><\/dd>\n<dt id=\"can%20i%20use%20this%20with%20next.js%20or%20other%20frontend%20frameworks%3F\"><h3>Can I use this with Next.js or other frontend frameworks?<\/h3><\/dt>\n<dd><p>Yes! The plugin sends correct CORS headers and returns standard JSON responses, making it compatible with any frontend framework or language that supports HTTP requests.<\/p><\/dd>\n<dt id=\"does%20it%20support%20public%2Fprivate%20keys%3F\"><h3>Does it support Public\/Private keys?<\/h3><\/dt>\n<dd><p>Yes, you can configure RS256 or ES256 algorithms in the settings and provide your PEM formatted keys for asymmetric signing.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<ul>\n<li><strong>Initial Release<\/strong>: Complete authentication suite with JWT, RBAC, SSO, and Security features.<\/li>\n<li><strong>Security<\/strong>: Added Brute Force protection, Device Limits, and Security Webhooks.<\/li>\n<li><strong>API<\/strong>: Full set of endpoints for Login, Register, Password Reset, and Token Management.<\/li>\n<\/ul>","raw_excerpt":"A complete authentication solution for Headless WordPress applications using JWT, supporting Registration, SSO, RBAC, and advanced Security features.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/dv.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/267231","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dv.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/dv.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/dv.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=267231"}],"author":[{"embeddable":true,"href":"https:\/\/dv.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/hidayatsafewp"}],"wp:attachment":[{"href":"https:\/\/dv.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=267231"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/dv.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=267231"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/dv.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=267231"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/dv.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=267231"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/dv.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=267231"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/dv.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=267231"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}