Summary
Two response-shape bugs in the multiFactorAuth auth-factors endpoints, found while pointing @workos-inc/node's User Management SDK at the emulator for TOTP enrolment/deletion.
Environment: @workos/emulate@0.7.1, @workos-inc/node@10.13.0, Node v24.
Bug 1 — createUserAuthFactor response is missing the documented envelope (still reproduces)
POST /user_management/users/:id/auth_factors returns a bare authentication_factor object at the top level:
{"object":"authentication_factor","user_id":"user_01M28GY2WN7GGHA3NN0KJHWJXG","type":"totp","totp":{"issuer":"...","user":"...","uri":"otpauth://totp/...?secret=...&issuer=..."},"id":"auth_factor_01M28GY2X5K87SBN8W1DPYDM0Y","created_at":"...","updated_at":"..."}
The Node SDK's multiFactorAuth.createUserAuthFactor expects { authentication_factor, authentication_challenge } and throws before returning:
TypeError: Cannot read properties of undefined (reading 'object')
at deserializeFactorWithSecrets$1 (.../@workos-inc/node/lib/factory-*.mjs:857:17)
at MultiFactorAuth.createUserAuthFactor (.../@workos-inc/node/lib/factory-*.mjs:4654:26)
Repro (minimal, using the SDK directly against a local createEmulator() instance):
const user = await workos.userManagement.createUser({ email, password, emailVerified: true });
await workos.multiFactorAuth.createUserAuthFactor({
userId: user.id,
type: 'totp',
totpIssuer: 'Acme',
totpUser: email,
}); // throws TypeError before returning
This makes it impossible to drive TOTP enrolment through the emulator via the SDK at all — a consumer has to fall back to mocking the SDK call entirely, which defeats the purpose of testing against a real wire format.
Bug 2 — deleteFactor's 204 has the wrong Content-Type (no longer breaks the SDK, but still non-conformant)
DELETE /auth/factors/:id performs the delete correctly (confirmed: a subsequent login for that user no longer raises an MFA challenge) but answers 204 with Content-Type: text/plain; charset=UTF-8 instead of application/json (or no body/no content-type):
raw DELETE status: 204
raw DELETE content-type: text/plain; charset=UTF-8
On @workos-inc/node@10.10.0 this made multiFactorAuth.deleteFactor throw (TypeError: Cannot read properties of undefined (reading 'slice')). Re-tested just now against 10.13.0 and the SDK no longer throws — it appears to have been hardened to tolerate a non-JSON 204 body. So this no longer blocks SDK-based testing, but the emulator's response still doesn't match what I'd expect production WorkOS to return for a 204, and it's worth fixing at the source in case another language SDK is less forgiving.
Suggested fix
createUserAuthFactor's route handler should wrap the created factor in { authentication_factor, authentication_challenge } the way the docs describe, generating a matching authentication_challenge alongside the factor.
deleteFactor's route handler should send the 204 with no body and no (or a JSON) Content-Type header, matching a standard no-content response.
Happy to open a PR if a maintainer can confirm the intended envelope shape for createUserAuthFactor (I don't have a real WorkOS account to check production's exact response).
Summary
Two response-shape bugs in the
multiFactorAuthauth-factors endpoints, found while pointing@workos-inc/node's User Management SDK at the emulator for TOTP enrolment/deletion.Environment:
@workos/emulate@0.7.1,@workos-inc/node@10.13.0, Node v24.Bug 1 —
createUserAuthFactorresponse is missing the documented envelope (still reproduces)POST /user_management/users/:id/auth_factorsreturns a bareauthentication_factorobject at the top level:{"object":"authentication_factor","user_id":"user_01M28GY2WN7GGHA3NN0KJHWJXG","type":"totp","totp":{"issuer":"...","user":"...","uri":"otpauth://totp/...?secret=...&issuer=..."},"id":"auth_factor_01M28GY2X5K87SBN8W1DPYDM0Y","created_at":"...","updated_at":"..."}The Node SDK's
multiFactorAuth.createUserAuthFactorexpects{ authentication_factor, authentication_challenge }and throws before returning:Repro (minimal, using the SDK directly against a local
createEmulator()instance):This makes it impossible to drive TOTP enrolment through the emulator via the SDK at all — a consumer has to fall back to mocking the SDK call entirely, which defeats the purpose of testing against a real wire format.
Bug 2 —
deleteFactor's204has the wrongContent-Type(no longer breaks the SDK, but still non-conformant)DELETE /auth/factors/:idperforms the delete correctly (confirmed: a subsequent login for that user no longer raises an MFA challenge) but answers204withContent-Type: text/plain; charset=UTF-8instead ofapplication/json(or no body/no content-type):On
@workos-inc/node@10.10.0this mademultiFactorAuth.deleteFactorthrow (TypeError: Cannot read properties of undefined (reading 'slice')). Re-tested just now against10.13.0and the SDK no longer throws — it appears to have been hardened to tolerate a non-JSON204body. So this no longer blocks SDK-based testing, but the emulator's response still doesn't match what I'd expect production WorkOS to return for a204, and it's worth fixing at the source in case another language SDK is less forgiving.Suggested fix
createUserAuthFactor's route handler should wrap the created factor in{ authentication_factor, authentication_challenge }the way the docs describe, generating a matchingauthentication_challengealongside the factor.deleteFactor's route handler should send the204with no body and no (or a JSON)Content-Typeheader, matching a standard no-content response.Happy to open a PR if a maintainer can confirm the intended envelope shape for
createUserAuthFactor(I don't have a real WorkOS account to check production's exact response).