Repository navigation
Conversation
…skipping them WorkOS answers authenticate with mfa_challenge / mfa_enrollment errors, not a pending token in a success body. LoginCompleter now reads the step from the error (MfaStep), so the sign-in form shows the code prompt and the profile's factor allowlist applies. mfa_enrollment is refused with a clear 403 until the form can enroll a factor. - enforce=always no longer rejects the response from a correct code - headless wp-login.php refuses an MFA step past WP's own password handlers, which ignored the earlier WP_Error and signed the user in - the login button and the AuthKit password route stop treating an MFA step as a wrong password
…onse
Challenge, verify and factor delete went to /user_management/... paths
WorkOS doesn't serve. Factors enrolled through User Management are MFA API
factors, so they go to /auth/factors/{id}/challenge,
/auth/challenges/{id}/verify and /auth/factors/{id} (matches workos-php's
MultiFactorAuth service). TOTP enroll now reads the factor from
authentication_factor and returns the challenge WorkOS creates with it.
This was referenced Oct 18, 2026
wp_json_encode( [] ) is [], and WorkOS answers 422 "Validation failed"
to it. A TOTP challenge (POST /auth/factors/{id}/challenge, no SMS
template) always had an empty body, so the code step could never start.
Found on a live run against WorkOS staging; empty bodies are now {}.
bordoni
marked this pull request as ready for review
October 19, 2026 05:27
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
MFA on
maincan't work against real WorkOS. This fixes the sign-in side, so the rest of the 1.1.0 MFA work (#28) builds on calls that actually reach WorkOS.Changes
authenticatewith anmfa_challengeormfa_enrollmenterror, not a success carrying a pending token.LoginCompleteronly looked at successes, so users saw WorkOS's raw error. The newAuth\AuthKit\MfaStepreads the step off the error:mfa_challengebecomes the existing code step (the profile's factor allowlist still applies), andmfa_enrollmentreturns403 workos_authkit_mfa_enrollment_requireduntil the sign-in form can enroll a factor./user_management/auth_factors/…and/user_management/auth_challenges/…, which WorkOS doesn't serve. Factors enrolled through User Management are MFA API factors, so the calls now go to/auth/factors/{id}/challenge,/auth/challenges/{id}/verifyand/auth/factors/{id}(the same paths asworkos-php'sMultiFactorAuthservice).POST /auth/mfa/totp/enrollread the factor from the wrong level of the response (WorkOS nests it underauthentication_factor), so the QR code and secret came back empty. It now reads them correctly and also returns thechallenge_idWorkOS creates with the factor.enforce = alwaysaccepts a correct code. The response to a verified code has no pending token, and thealwayscheck read that as "no factor".POST /auth/mfa/verifynow tellscomplete()the second factor was satisfied.wp-login.php, an MFA error was treated like a wrong WorkOS password, and core's own password check at priority 20 (which ignores an earlierWP_Error) then signed the user in with no second factor. The filter now refuses with403 workos_mfa_step_unsupportedand re-applies the refusal after core's handlers. The login button's form gives the same message, and the AuthKit password route no longer re-syncs the password to WorkOS when only the second factor is missing.Verified
MfaLoginErrorsTest(10 tests) feeds the error shape the API client really produces: challenge and enrollment errors, the factor allowlist, no token leak on enrollment,alwayswith a satisfied factor, and headlesswp_authenticate()refusing an MFA step while still falling back for a wrong WorkOS password.AuthKitRestMfaTest(always+ verify succeeds, a wrong code still fails) andAuthKitRestPasswordTest(mfa_challengesurfaces and skips the WP fallback).ApiClientAuthKitTestasserts the/auth/...paths.mainon the local runner (constants and "plugin disabled" cases). CI is authoritative.Not in this PR
/user_management/users/{id}/auth_factors, which WorkOS documents as TOTP-only. MFA in 1.1.0 is TOTP.Part of #28