1.0.5 – 2026-05-18
- New: WorkOS → Users admin page. Paginated, searchable React list of WorkOS users for the active environment, with a per-row “Open in WorkOS” deep-link straight to the user’s Dashboard page. Lets admins triage WorkOS users (including re-enabling a suppressed email under the Dashboard’s Emails tab) without bouncing through the Dashboard’s own user picker. Requires manage_options. No bulk re-enable yet — WorkOS does not expose a public REST endpoint for the “Re-enable email” action. (CONS-273)
- New: Admin-triggered WorkOS password reset. A user with edit_user capability on a linked target (which includes self-service, since WP grants edit_user on one’s own ID) can send a WorkOS reset email via three surfaces — a row action on wp-admin/users.php, a “Password Reset” panel on the user-edit screen, and the new [workos:password-reset] shortcode. The shortcode supports both admin-of-other (user=”…”) and self-service (no user attr) modes. (#21)
- New: redirect_url parameter on the admin REST endpoint and on the existing public reset endpoints. The value is validated against home_url() host, threaded through the WorkOS-hosted email link, and used by the AuthKit React shell to send the user to the chosen page after a successful reset. Fixes the CONS-287 regression where the post-reset URL was unconfigurable.
- New: WorkOS reset emails now point at the in-site React reset page (/workos/login/{slug}?token=…&redirect_to=…) instead of wp-login.php. The old wp-login.php?workos_action=reset-password URL still resolves cleanly so any reset emails already in users’ inboxes keep working.
- New: Password strength + confirmation on the reset-confirm step. Users must enter the new password twice; the value is scored in real time via WordPress’s wp.passwordStrength.meter (zxcvbn) and the submit button stays disabled until the fields match and the score reaches Strong. Site name and common words are passed as the zxcvbn disallowed list.
- New: Per-profile auto_login_after_reset toggle (default on). When enabled, a successful password reset signs the user in (via the shared LoginCompleter, so MFA / organization selection / entitlement gates still apply) and lands them on the validated post-reset redirect URL. With the toggle off the user lands on the existing “Password reset — Continue to sign in” card.
- New: Password reset mirrors the new password to the linked WordPress user via wp_set_password() so the WP password fallback (?fallback=1, wp_authenticate, REST app passwords) stays in sync with the WorkOS password the user just typed. Unlinked users no-op cleanly.
- New: Skeleton placeholders on every AuthKit surface (wp-login.php takeover, /workos/login/{profile}, and the shortcode) paint a card-shaped silhouette with shimmering rows the moment the page lands, instead of a blank gap while the React bundle downloads and bootstraps. Heights match the hydrated form one-to-one so the swap is a flicker, not a layout jump. Honours prefers-reduced-motion.
1.0.4 – 2026-05-14
- Fix: wp-login.php?loggedout=true is now claimed by the AuthKit takeover instead of rendering native wp-login. The “you have been logged out” screen advertised the wp-login username/password field, which legacy customers misread as a still-working classic sign-in. The URL now 302s to /login/?loggedout=true (or the configured custom path) so the React form handles it. ?fallback=1, ?workos=0, and action=logout|lostpassword|rp|… bypasses are unchanged. (#18)
- Fix: WorkOS password reset emails arrived with HTML-escaped query separators (?workos_action=…&profile=…&token=…) when a home_url/login_url filter on the host ran the URL through esc_url(). The plugin now decodes HTML entities in build_password_reset_url() before posting to WorkOS so the emailed link is valid. (#17)
- Fix: prevent infinite login redirect loops by sending Cache-Control: no-store / Pragma: no-cache headers on auth redirects so cached responses do not trap the browser in a redirect cycle when returning to a previously visited URL. (#15)
- Fix: unchecking an auth method or MFA factor on a Login Profile now persists. update_profile‘s array_replace_recursive($existing, $params) merge preserved trailing entries from the existing list when the incoming list was shorter, so removed methods reappeared after save. The REST update now explicitly overwrites methods and mfa.factors from the payload (using array_key_exists() so an empty array is honored). Other scalar/associative fields are unaffected. (#14)
1.0.3 – 2026-05-12
- Fix: AuthKit login flows now recover transparently from WorkOS organization_selection_required. When the Login Profile has an organization pinned (with Config::get_organization_id() as a fallback), the plugin re-authenticates via the organization-selection grant instead of surfacing “The user must choose an organization to finish their authentication.” to the user.
- Fix: pre-existing WordPress users who joined before an organization was pinned are now auto-enrolled into the pinned WorkOS organization. The plugin creates the WorkOS membership and retries the authenticate call when (and only when) a matching local WP user exists and the WorkOS error body carries the authenticated user_id. Membership creation and the entity_already_exists short-circuit are logged via workos_log() (visible under WP_DEBUG / WORKOS_DEBUG). Strangers and ambiguous lookups still get a clean pinned_org_mismatch error — no email-lookup guessing.
- Fix: the legacy OAuth callback at /workos/callback now routes through LoginCompleter, so it shares the same organization_selection_required recovery, MFA gating, and post-login bookkeeping as the AuthKit REST endpoints. The callback no longer short-circuits on the WorkOS error and discards the OAuth code. Legacy AuthKit-redirect callbacks (no profile slug in state) keep their original redirect contract — the state-supplied redirect_to still wins over the default profile’s post_login_redirect.
1.0.2 – 2026-05-11
- New: WordPress password fallback — if WorkOS rejects a password, the auth endpoint can retry against WordPress’s own wp_authenticate() to cover users whose passwords were never synced to WorkOS, then link the user to WorkOS and (by default) write the password through so future logins authenticate directly. A new “Require Email Confirmation on Fallback” setting switches the post-fallback step to a magic-code email instead of syncing the plaintext password. Gated by the existing allow_password_fallback toggle.
- New: wp-config.php constant seeder — defining WORKOS_* (or env-scoped WORKOS_{PRODUCTION|STAGING}_*) constants now seeds those values into the database on boot, so the admin UI reflects them. Covers string credentials, the new boolean toggles, and WORKOS_REDIRECT_URLS arrays. Hash-skipped when nothing has changed — one autoloaded option read per request in steady state.
- Fix: Auth REST endpoints under /wp-json/workos/v1/auth/* now read the nonce from X-WorkOS-Nonce instead of X-WP-Nonce to avoid a header collision with WordPress core and other plugins. The bundled React shell is updated; external clients hitting these endpoints directly must rename the header.
1.0.1 – 2026-05-01
- New: Organization tab — manual Refresh button next to the organization dropdown re-fetches organizations from WorkOS on demand via the admin REST endpoint (no admin-ajax), bypassing the 5-minute cache. The dropdown is blocked with a spinner during the refresh and the selected organization is preserved when it still exists.
- New: ?refresh=1 query parameter on GET /wp-json/workos/v1/admin/profiles/organizations to drop the shared transient before fetching.
- Fix: Organization tab — “Save Settings” was blocked by a hidden, required org_name input. The Create Organization modal is now rendered at admin_footer so its inner <form> is no longer nested inside the settings form.
- Fix: Active environment is now stored in a single place. The admin Settings UI wrote to workos_active_environment while the runtime auth flow read from workos_global[‘active_environment’], so picking “Production” still loaded staging credentials and redirected to the staging AuthKit. The runtime now reads/writes the standalone option, with a one-time migration (db_version 2 → 3) that moves any legacy value out of workos_global.
1.0.0 – 2026-04-23
Custom AuthKit (WordPress-hosted login):
* React login shell on wp-login.php, [workos:login] shortcode, and /workos/login/{profile} route.
* Login Profiles — admin-defined presets for enabled methods, pinned organization, signup/invite/reset flows, MFA policy, and branding, managed at WorkOS → Login Profiles.
* Per-profile custom URL paths (e.g. /members, /team/login) on top of the canonical /workos/login/{slug} rewrite. The default profile can claim a custom path so /wp-login.php bounces to it. Reserved core paths are blocked.
* Already-signed-in visitors are 302’d to their post-login destination on every AuthKit surface (or shown an inline “You’re already signed in” notice in the shortcode).
* Per-profile forward_query_args toggle to pass marketing/analytics args onto the post-login destination (internals always stripped).
* Pinned-organization picker in the Profile editor reads live from WorkOS (with a “Custom ID…” fallback for legacy or unlisted orgs), and the Profiles list renders organization names instead of raw IDs.
* Embed & URLs section in the editor exposes copyable input fields for the canonical URL, the optional custom-path URL, and the [workos:login profile=”…”] shortcode.
* Sign-in methods: email + password, magic code, social OAuth (Google, Microsoft, GitHub, Apple), passkey.
* Full MFA support — TOTP, SMS, WebAuthn/passkey with in-app enrollment + challenge.
* Self-serve sign-up, invitation acceptance, and in-app password reset.
* Branding — heading, subheading, primary color (defaults to WordPress admin-color palette), and three-mode logo control (default falls back to Site Icon → bundled WP logo, custom uses the chosen attachment, none hides the logo).
* SlotFill extensibility — ten named slots (including workos.authkit.belowCard, which renders standard wp-login.php links by default) for plugins to inject React elements into the login UI.
* Profile routing rules (redirect_to glob / referrer host / user role).
* WorkOS Radar anti-fraud integration (set WORKOS_RADAR_SITE_KEY).
* Public REST at /wp-json/workos/v1/auth/* with profile-scoped nonces, per-IP/per-email rate limits, and signature-verified tokens.
* Full browser internationalization — every user-facing React/TS/JS string ships through @wordpress/i18n with the integration-workos text domain and wp_set_script_translations() wiring.
Base platform:
* SSO login via WorkOS AuthKit (legacy redirect mode, per-profile selectable).
* Headless authentication via WorkOS API.
* Directory Sync (SCIM) for automatic user provisioning and deprovisioning.
* Role mapping between WorkOS organization roles and WordPress roles.
* Organization management with local caching and multisite support.
* Entitlement gate — require organization membership to log in.
* Webhook processing for user, organization, directory, membership, and connection events.
* REST API Bearer token authentication using WorkOS access tokens.
* Legacy login button Gutenberg block and classic widget (AuthKit-redirect flow).
* Login bypass via ?fallback=1 for native WordPress login when WorkOS is unavailable.
* Activity logging with local database table and admin viewer.
* Audit logging — forward WordPress events to WorkOS Audit Logs.
* Role-based login redirects with per-role URL configuration.
* Role-based logout redirects with per-role URL configuration.
* Password reset integration with WorkOS.
* Registration redirect to WorkOS AuthKit.
* Admin bar badge showing active environment (production/staging).
* Diagnostics page with health checks and connectivity tests.
* Onboarding wizard for guided first-time setup.
* WP-CLI commands for status, user management, organization management, and bulk sync.