Skip to content

MFA auth-factors: createUserAuthFactor omits the documented envelope (SDK throws); deleteFactor's 204 has the wrong Content-Type #110

Description

@georgedonnelly

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).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions