Skip to content

fix(auth0-auth-js): derive challenge type from authenticator_type and oob_channel#165

Open
GuaiamumSuspeito wants to merge 2 commits into
auth0:mainfrom
GuaiamumSuspeito:fix/mfa-get-authenticators-type-mapping
Open

fix(auth0-auth-js): derive challenge type from authenticator_type and oob_channel#165
GuaiamumSuspeito wants to merge 2 commits into
auth0:mainfrom
GuaiamumSuspeito:fix/mfa-get-authenticators-type-mapping

Conversation

@GuaiamumSuspeito
Copy link
Copy Markdown

Description

mfa.getAuthenticators() in @auth0/auth0-spa-js always returns an empty array, even when the user has active MFA authenticators enrolled.

The bug spans two packages:

Layer 1 — @auth0/auth0-auth-js (this fix): transformAuthenticatorResponse in utils.ts maps api.type to the response, but the Auth0 GET /mfa/authenticators endpoint does not return a type field. Per the official API docs, the response uses authenticator_type and oob_channel:

[
  {"authenticator_type": "recovery-code", "id": "recovery-code|dev_...", "active": true},
  {"authenticator_type": "otp", "id": "totp|dev_...", "active": true},
  {"authenticator_type": "oob", "oob_channel": "sms", "id": "sms|dev_...", "name": "+1123XXXXX", "active": true}
]

Since api.type is always undefined, every transformed authenticator has type: undefined.

Layer 2 — @auth0/auth0-spa-js (downstream): MfaApiClient.getAuthenticators filters authenticators with if (!auth.type) return false, which rejects everything because type is always undefined.

The fix adds a deriveChallengeType(authenticatorType, oobChannel) function that maps the API fields to the challenge types auth0-spa-js expects:

authenticator_type oob_channel Derived type
otp otp
recovery-code recovery-code
oob sms phone
oob voice phone
oob auth0 push-notification
oob email email

Also adds oob_channel (singular) to AuthenticatorApiResponse and exports a new ChallengeType union type.

References

Testing

Added 8 unit tests for deriveChallengeType covering all authenticator type / OOB channel combinations and edge cases (unknown types, missing channel). Updated existing listAuthenticators tests to assert the derived type values ('otp', 'phone') instead of undefined. Updated mock data to include oob_channel to match real API response shapes.

All 146 existing tests pass.

  • This change adds test coverage for new/changed/fixed functionality

Checklist

  • I have added documentation for new/changed functionality in this PR or in auth0.com/docs
  • All active GitHub checks for tests, formatting, and security are passing
  • The correct base branch is being used, if not the default branch

… oob_channel

`transformAuthenticatorResponse` was copying `api.type`, a field the
Auth0 GET /mfa/authenticators endpoint never returns. This caused every
authenticator's `type` to be `undefined`, which made auth0-spa-js's
`getAuthenticators()` filter out all results and return an empty array.

The fix derives `type` from `authenticator_type` and `oob_channel` using
a new `deriveChallengeType` helper, matching the challenge types that
downstream consumers expect (otp, recovery-code, phone,
push-notification, email).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Author

@GuaiamumSuspeito GuaiamumSuspeito left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self-review

Comment thread packages/auth0-auth-js/src/mfa/types.ts Outdated
…mments

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@GuaiamumSuspeito GuaiamumSuspeito marked this pull request as ready for review April 15, 2026 23:54
/** Additional type information */
type?: string;
/** Challenge type derived from authenticator_type and oob_channel */
type?: ChallengeType;
Copy link
Copy Markdown
Author

@GuaiamumSuspeito GuaiamumSuspeito Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a library API break, not sure what's the approach on API breaks for the repo, but if you'd rather avoid it than doing a major bump or breaking consumers, we can keep it as a plain string and leave the conversion to @auth0/auth0-spa-js

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant