Everything in v4
API Keys
Create long-lived, scoped credentials for server-to-server integrations, CI/CD pipelines, and third-party services - no JWT expiry management needed.
- Scoped permissions: read, create, update, delete
- SHA-256 hashed - the key is never stored in plain text
- Revoke or expire keys at any time
- JWT authentication also accepted on the /api-keys endpoint
- Non-admin users can manage their own keys without admin access
OAuth: 4 Providers
Users can sign in with Google, Auth0, Facebook, or GitHub and receive a WordPress JWT - no password form required.
- Google: authorization code or ID token (Sign In With Google)
- Auth0: authorization code flow
- Facebook: authorization code flow
- GitHub: authorization code flow
- Auto-register users if no matching account exists
Multiple JWT Decryption Keys
Define multiple decryption keys and let the plugin pick the right one automatically based on the JWT header or payload.
- Key selection based on JWT header or payload field
- Supports HS256/384/512 and RS256/384/512 per key
- Seamless key rotation without breaking existing tokens
Audit Logs
Every authentication event - logins, token issues, revocations, and errors - is now logged for auditing and debugging.
- Logs login, register, delete, OAuth, 2FA, and token events
- Searchable from the WordPress admin
- Configurable retention period
Webhooks
Fire HTTP callbacks on authentication events - integrate with Slack, logging services, or any external system in real time.
- Configurable per event type
- Custom URL, method, headers, and JSON payload
- Works with any HTTP endpoint
Dashboard
A new at-a-glance status page shows every feature's state in one place - routes, security, integrations, and monitoring.
- All routes and their enabled/disabled state
- Security: CORS, Protect Endpoints, Auth Codes, API Keys
- Monitoring: Webhooks, Webhook Logs, Audit Logs
Redesigned Settings UI
The plugin admin panel has been fully redesigned - cleaner layout, better grouping, and less noise so you can find what you need faster.
- Reorganized sections for a more logical flow
- User identification consolidated in General settings
- Cleaner forms with improved field descriptions
- Light/Dark mode support
2FA Support
Require a second authentication step before issuing a full JWT - compatible with the WordPress Two Factor plugin.
- Interim JWT issued after password check; 2FA code completes the flow
- Dedicated POST /auth/2fa endpoint
- Configurable interim JWT TTL (1-60 minutes)
- Users without 2FA configured are unaffected
WooCommerce
Drive a WooCommerce store with a JWT instead of a consumer key/secret - manage products and run a fully headless cart & checkout with the token alone.
- JWT auth on every /wc/ route: CRUD (wc/v3) and the Store API (wc/store)
- Scoped to WooCommerce routes - works even with the global middleware off
- Optional Store API cart & checkout: header-JWT requests skip the CSRF nonce
- Admin / Shop Manager tokens manage the catalog; customers manage their own cart
Refresh Token
Refresh tokens are now more secure and configurable - rolling rotation, a separate encryption key, and custom payload support.
- Rolling rotation: each refresh issues a new token and invalidates the old one
- Separate refresh token secret key, independent of the JWT signing key
- Custom payload merged into the newly issued JWT on refresh
- Auth Code protection option for the refresh endpoint
JWT Decoder
Paste any JWT directly in the WordPress admin panel to inspect its header and payload - no external tools needed.
- Decodes header and payload instantly in the browser
- Token is never sent to the server
- Useful for debugging token claims and expiry
Code Examples
Every endpoint page in the plugin admin panel now shows ready-to-copy code snippets tailored to your current settings.
- cURL, PHP, and JavaScript examples per endpoint
- Examples use your configured namespace and site URL
- Auth Code and parameter values pre-filled from your settings
Protect Endpoints Redesign
Protect Endpoints has been rethought as a single ordered rules table - each rule sets access to Public, JWT required, or JWT + Roles, and the first matching rule wins.
- Unified rules table replaces separate whitelist and protected lists
- Per-rule access level: Public, JWT required, or JWT + specific Roles
- Top-to-bottom evaluation with first-match-wins logic
- Existing settings auto-migrate on first load
- Role names are validated against WordPress on save
Registration Enhancements
User registration is now more flexible - assign multiple default roles, trigger built-in WordPress notification emails, and use variables in reset password email subjects.
- Support multiple default user roles on registration
- Option to send the default WordPress welcome email on registration
- Option to send the default WordPress password-changed email from the change-password endpoint
- Variables now supported in the reset password email subject line
Granular Token Controls
Enable or disable refresh, revoke, and validate token endpoints independently - ship only the surface area your app needs.
- Toggle refresh token endpoint on/off
- Toggle revoke token endpoint on/off
- Toggle validate token endpoint on/off
- Optionally require the "Bearer" prefix in the Authorization header
Improvements & Code Quality
Standardized HTTP status codes across all endpoints and a cleaner, more maintainable internal codebase.
- All endpoints now respond with 400, 401, 403, 422, or 500 status codes
- Refactored internal service layer for better separation of concerns
- Improved unit test coverage across all core services
- Reduced code duplication across service classes
Breaking Changes
Most JWT flows continue to work without changes. Review these items before upgrading.
Register user response shape changed
POST /users used to return {"success":true,"ID":1,...}. It now returns {"success":true,"data":{"id":1,...}}. The user object is nested under "data", "ID" is lowercase "id", and several fields were renamed: user_login → login, user_nicename → nicename, user_email → email, user_url → url, user_registered → registered, user_activation_key → activation_key, user_status → status.
Action: Update any code that reads user fields from the register response - check both the new nesting under "data" and the renamed field keys.
Register User docsLegacy /register endpoint removed
The old POST /simple-jwt-login/v1/register route no longer exists. The canonical route is POST /simple-jwt-login/v1/users.
Action: Update all callers to use POST /simple-jwt-login/v1/users.
Register User docsUser Identification moved to General settings
The "User Identification" option (email, login, ID) has moved from the Delete User settings tab to the General settings tab. It now applies globally to all endpoints.
Action: After upgrading, verify the User Identification value in Settings → Simple JWT Login → General.
General settings docsSettings storage structure reorganized
The internal layout of plugin options in wp_options has changed. Existing settings are migrated automatically on first load, but the old keys are removed.
Action: Review every settings tab after upgrading to confirm values carried over correctly.
Authentication response now includes refresh_token
POST /auth returns a new "refresh_token" field when the refresh token feature is enabled. The JWT field itself is unchanged.
Action: No action needed unless your client strictly rejects unexpected response fields or you need to store the token.
Refresh Token docs2FA changes the /auth flow for affected users
Users with the Two Factor plugin configured now receive a short-lived interim JWT from /auth instead of a full JWT. A second request to POST /auth/2fa (with the interim JWT + 2FA code) is required to get the real token.
Action: Update your authentication flow to handle the interim JWT case, or leave 2FA disabled for API users.
2FA docsError response envelope: message and error_code moved under data
In v3, error responses had the form {"success":false,"message":"...","error_code":N}. In v4, both fields moved under a nested data object: {"success":false,"data":{"message":"...","error_code":N}}. Every endpoint follows this new shape.
Action: Update all error-handling code to read response.data.message and response.data.error_code instead of response.message and response.error_code.
Error codes docsProtected endpoint auth failures return 401 instead of 403
When the Protect Endpoint feature blocks an unauthenticated request, the plugin previously returned HTTP 403 Forbidden. It now returns HTTP 401 Unauthorized to align with the HTTP spec.
Action: Update any code that checks specifically for status 403 on protected routes to handle 401 instead.
Protect Endpoint docsError field renamed: errorCode → error_code
In v3, the error field in responses was named "errorCode" (camelCase). In v4, it is renamed to "error_code" (snake_case) to match the rest of the API's naming convention.
Action: Update all error-handling code that reads response.errorCode (or response.data.errorCode) to use error_code instead.
Error codes docsv3 is now in maintenance mode
We recommend upgrading to v4 as soon as possible. After January 31, 2027, v3.x will no longer receive any updates, including security patches.
v4.x
Active (LTS)New features, bug fixes, security patches, and WordPress compatibility fixes.
v3.x
MaintenanceSecurity patches and WordPress compatibility fixes only - no new features, no bug fixes. End of life: January 31, 2027.
Upgrading to v4
Most existing JWT flows continue to work without changes. Review the breaking changes section above before upgrading.
Download the plugin from GitHub and upload the zip via Plugins → Add New → Upload Plugin, or install it from the WordPress plugin directory.
The breaking changes are listed above. Address them before going to production - the error envelope change, the errorCode → error_code rename, the register response shape change, the removed /register route, and the relocated User Identification setting are the most likely to affect existing integrations.
Your settings are automatically migrated. Open Settings → Simple JWT Login and verify your values carried over correctly.
Enable API Keys, Webhooks, Audit Logs, 2FA, and the 4 OAuth providers from Settings → Simple JWT Login to start using the new capabilities.
v3 vs v4 Performance
Load-test results from 100 calls per endpoint on identical infrastructure. All endpoints returned 100% success rate except where noted.
| Endpoint | v3 | v4 | Delta (p95) | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Min | Avg | Median | P95 | Max | Min | Avg | Median | P95 | Max | ||
Register UserPOST /simple-jwt-login/v1/users | 0.370s | 0.471s | 0.418s | 0.906s | 1.406s | 0.233s | 0.255s | 0.255s | 0.273s | 0.286s | -70% |
Autologin with JWTGET /simple-jwt-login/v1/autologin | 0.114s | 0.133s | 0.127s | 0.174s | 0.224s | 0.113s | 0.125s | 0.122s | 0.134s | 0.310s | -23% |
Create Post (JWT)POST /wp/v2/posts (JWT bearer token) | 0.152s | 0.175s | 0.168s | 0.208s | 0.376s | 0.130s | 0.144s | 0.139s | 0.170s | 0.227s | -18% |
Create Post (API Key)1POST /wp/v2/posts (API key) | N/A | 0.133s | 0.160s | 0.144s | 0.279s | 0.357s | new | ||||
Validate TokenPOST /simple-jwt-login/v1/auth/validate | 0.080s | 0.088s | 0.087s | 0.101s | 0.111s | 0.084s | 0.090s | 0.088s | 0.098s | 0.120s | -3% |
Auth UserPOST /simple-jwt-login/v1/auth | 0.128s | 0.138s | 0.136s | 0.151s | 0.217s | 0.146s | 0.174s | 0.153s | 0.152s | 0.162s | +1% |
- API Keys did not exist in v3; the v3 run returned 0% success rate. v4 introduces this endpoint and handles it correctly.
Delta (p95) = (v4 p95 - v3 p95) / v3 p95 × 100. Negative values mean v4 is faster.
Try v4 today
Simple JWT Login v4 is free, open-source, and available now.