feat(mfa): Implement Multi-Factor Authentication (MFA) support#1517
feat(mfa): Implement Multi-Factor Authentication (MFA) support#1517subhankarmaiti wants to merge 29 commits into
Conversation
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
| ) | ||
| } | ||
|
|
||
| fun enroll(mfaToken: String, type: String, value: String?, promise: Promise) { |
There was a problem hiding this comment.
Define type as enum so that its always limited to the supported factor
There was a problem hiding this comment.
At the bridge boundary, the param has to stay String. React Native TurboModule codegen marshals primitives across the JS↔native boundary.
For consumers, the real type-safety lives in the TS layer, which exposes a public MfaFactorType
| } | ||
| } | ||
|
|
||
| func enroll(mfaToken: String, type: String, value: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { |
There was a problem hiding this comment.
Make type as an enum instead of String
There was a problem hiding this comment.
For consumer side it already exposing the enum MfaFactorType. which throw compile time error if passed any other strings.
71772d0 to
714794d
Compare
…into feat/flexible-factors-grant-support
…into feat/flexible-factors-grant-support
…into fix/multi-tenant-domain-switching
…pdate Auth0Provider to use it
…sage of credentialsManagerStorageKey
…into fix/multi-tenant-domain-switching
… for multi-tenant support
…auth0/react-native-auth0 into feat/flexible-factors-grant-support
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds MFA Flexible Factors Grant support across shared types, native and web bridge layers, React client wiring, example MFA flows, and docs. Also threads ChangesMFA Flexible Factors Grant and per-client credential storage
Sequence Diagram(s)sequenceDiagram
participant App as App code
participant Provider as Auth0Provider
participant Client as NativeAuth0Client or WebAuth0Client
participant Mfa as Platform MFA adapter
participant Bridge as Native bridge
participant SDK as Auth0 SDK
App->>Provider: mfa.getAuthenticators(mfaToken)
Provider->>Client: getAuthenticators(...)
Client->>Mfa: getAuthenticators(...)
Mfa->>Bridge: getMfaAuthenticators(...) / spaMfa.getAuthenticators(...)
Bridge->>SDK: platform MFA call
SDK-->>Bridge: authenticators
Bridge-->>Provider: result
App->>Provider: mfa.verify(...)
Provider->>Client: verify(...)
Client->>Mfa: verify(...)
Mfa->>Bridge: mfaVerify(...)
Bridge->>SDK: verify credentials
SDK-->>Provider: credentials
Provider->>Provider: saveCredentials + LOGIN_COMPLETE
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 17
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
android/src/main/oldarch/com/auth0/react/A0Auth0Spec.kt (1)
204-209: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winRestore the bridge annotations for
passkeyEnrollmentChallenge.Without
@ReactMethod/@DoNotStrip, this method won’t be exported on Android old architecture, while the JS spec and bridge still exposepasskeyEnrollmentChallenge.Proposed fix
+ `@ReactMethod` + `@DoNotStrip` abstract fun passkeyEnrollmentChallenge( accessToken: String, userIdentity: String?, connection: String?, promise: Promise )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@android/src/main/oldarch/com/auth0/react/A0Auth0Spec.kt` around lines 204 - 209, The Android old-architecture bridge method passkeyEnrollmentChallenge in A0Auth0Spec is missing the annotations needed for export. Add back the React Native bridge annotations on this abstract method so it remains discoverable from JS, using the same pattern as the other bridged methods in A0Auth0Spec, specifically `@ReactMethod` and `@DoNotStrip`.
🧹 Nitpick comments (5)
src/types/parameters.ts (1)
286-288: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider typing
factorsAllowedasMfaFactorType[].
factorsAllowed?: string[]loses the discriminant typing already used elsewhere in this file. If the values are intended to be factor types, aMfaFactorType[](or the literal union) gives callers autocomplete and prevents typos.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/types/parameters.ts` around lines 286 - 288, The MfaGetAuthenticatorsParameters type is using a loose string[] for factorsAllowed, which drops the factor discriminant typing used elsewhere. Update factorsAllowed in MfaGetAuthenticatorsParameters to use MfaFactorType[] (or the existing literal union type if that is the canonical form) so callers get autocomplete and type safety, and make sure any related references in this file stay consistent with the MFA factor type definitions.src/core/models/MfaError.ts (1)
70-70: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueStrengthen typing of the error-code map and
type.
ERROR_CODE_MAP: Record<string, string>andtype: stringdiscard the literal information already encoded inMfaErrorCodes. Typing the values as(typeof MfaErrorCodes)[keyof typeof MfaErrorCodes]letse.type === MfaErrorCodes.INVALID_OTPcomparisons stay type-safe for consumers.♻️ Suggested typing
+type MfaErrorCode = (typeof MfaErrorCodes)[keyof typeof MfaErrorCodes]; + -const ERROR_CODE_MAP: Record<string, string> = { +const ERROR_CODE_MAP: Record<string, MfaErrorCode> = {- public readonly type: string; + public readonly type: MfaErrorCode;As per coding guidelines: "Avoid using
anytypes; use strict TypeScript typing instead".Also applies to: 141-151
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/core/models/MfaError.ts` at line 70, Strengthen the typing in MfaError by replacing the broad string-based declarations for ERROR_CODE_MAP and the error type with the literal union derived from MfaErrorCodes, so consumers keep type-safe comparisons like e.type === MfaErrorCodes.INVALID_OTP. Update the MfaError class and any related constructor/field typings in the MfaError implementation to use the inferred value type from MfaErrorCodes instead of string, and make sure the map preserves the existing enum-like literals throughout the code paths referenced by MfaErrorCodes and MfaError.Source: Coding guidelines
src/platforms/native/adapters/NativeMfaClient.ts (1)
21-108: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDocument the exported MFA adapter.
NativeMfaClientis part of the public native adapter surface now, but the class and its public methods were added without JSDoc. Please add API docs here so the new MFA bridge contract is discoverable and consistent with the rest ofsrc/**/*.ts. As per coding guidelines,src/**/*.ts:Use JSDoc comments to document all public APIs.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/platforms/native/adapters/NativeMfaClient.ts` around lines 21 - 108, The exported NativeMfaClient adapter is public but its API is undocumented; add JSDoc to the class and each public method (constructor, getAuthenticators, enroll, challenge, and verify) so the MFA bridge contract is discoverable and matches the documentation style used across src/**/*.ts. Include brief descriptions of each method’s purpose, parameters, and return values, and keep the docs aligned with the existing IMfaClient/INativeBridge terminology to make the adapter surface consistent.Source: Coding guidelines
src/platforms/web/adapters/WebMfaClient.ts (2)
44-46: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value
factorsAllowedfilter is silently dropped.
MfaGetAuthenticatorsParametersaccepts an optionalfactorsAllowed, but onlyparameters.mfaTokenis forwarded tospaMfa.getAuthenticators. Callers passing a filter will receive an unfiltered list. Either apply the filter client-side or document that the web platform ignores it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/platforms/web/adapters/WebMfaClient.ts` around lines 44 - 46, The WebMfaClient.getAuthenticators path is dropping the optional factorsAllowed filter because only parameters.mfaToken is passed into spaMfa.getAuthenticators. Update WebMfaClient so it either forwards or applies parameters.factorsAllowed before returning authenticators, using the existing MfaGetAuthenticatorsParameters and getAuthenticators symbols to locate the change. If filtering cannot be supported on web, make that behavior explicit instead of silently ignoring it.
73-76: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAvoid
anyfor the spa request payloads.
spaParamsis typedany, which suppresses type checking against the spa-js request types. Prefer the concrete spa-js parameter type (or a discriminated local type) so payload mismatches are caught at compile time.As per coding guidelines: "Avoid using
anytypes; use strict TypeScript typing instead."Also applies to: 152-152
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/platforms/web/adapters/WebMfaClient.ts` around lines 73 - 76, Avoid using any for the spa request payloads in WebMfaClient by replacing spaParams with the appropriate spa-js parameter type or a strict local discriminated union so TypeScript can validate the request shape. Update the mfaToken/factorType payload construction in the affected WebMfaClient methods (including the other matching spaParams assignment) to use concrete typing and keep the payload compatible with the spa-js request APIs.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@android/src/main/java/com/auth0/react/MfaClient.kt`:
- Around line 58-68: The factor normalization in mapFactorType() is incorrectly
collapsing voice into sms, which causes voice-only options to be exposed as SMS
authenticators. Update mapFactorType() in MfaClient to preserve voice as its own
factor instead of mapping it to sms, while keeping the existing mappings for
otp, sms, email, push, oob, and recovery-code unchanged.
In `@example/src/App.web.tsx`:
- Around line 453-456: The QR image generation in the App.web.tsx TOTP
enrollment flow is leaking the secret by sending enrollmentChallenge.barcodeUri
to a third-party service. Update the Image usage in the enrollment UI to avoid
remote QR generation: use a local/in-app QR renderer or remove the QR image
entirely and present only the deep link/secret, and apply the same change
anywhere else the same pattern appears in the enrollment screen.
In `@example/src/screens/class-based/ClassApiTests.tsx`:
- Around line 182-185: The MFA verification flow in ClassApiTests and the
runTest helper is exposing raw credential-bearing results from
auth0.mfa().verify(), which can leak sensitive tokens into logs and UI. Update
the Verify OTP path to sanitize the returned value before passing it to runTest,
and ensure runTest only logs/displays a redacted summary rather than the full
verification response. Use the auth0.mfa().verify call site and runTest as the
key places to apply the redaction.
- Line 153: The MFA enrollment call in ClassApiTests is using the wrong property
name and the verification flow is leaking returned credentials through runTest.
Update the auth0.mfa().enroll invocation to use factorType instead of type, and
adjust the nearby mfa().verify path so it is not wrapped in runTest when it
returns credentials; keep the tokens out of console/UI exposure by handling that
result internally in the test helper or directly awaiting it.
In `@example/src/screens/class-based/ClassLogin.tsx`:
- Around line 418-421: The QR image generation in ClassLogin’s Image source is
leaking the TOTP secret by sending enrollmentChallenge.barcodeUri to a
third-party service. Replace the api.qrserver.com URL usage with an in-app/local
QR renderer, or remove the QR image entirely and present only the deep link or
secret locally. Keep the fix within the ClassLogin component where the
enrollment QR is rendered so the secret never leaves the device.
- Around line 259-272: After mfaClient.verify succeeds in ClassLogin, the flow
only updates local state and never completes authentication. Update the MFA
success branch to persist the returned credentials and trigger the same
post-login navigation used by the password-login success path, rather than only
calling setResult and setMfaStep('complete'). Use the existing login success
handling in ClassLogin as the reference so the user is fully authenticated and
redirected after MFA.
In `@example/src/screens/hooks/Home.tsx`:
- Around line 482-485: The QR image generation in Home uses the third-party
api.qrserver.com URL with enrollmentChallenge.barcodeUri, which leaks the TOTP
secret off-device. Update the Image rendering path to avoid sending barcodeUri
to an external service; instead use an in-app/local QR renderer, or remove the
QR image and present only the deep link/secret in this screen. Keep the fix
localized around the enrollmentChallenge.barcodeUri usage in Home.tsx.
In `@EXAMPLES-WEB.md`:
- Around line 275-276: The web direct-auth note conflicts with the support
matrix for auth.passwordRealm(), so update the documentation to state one
consistent behavior across both places. Use the relevant auth method references
in EXAMPLES-WEB.md, especially auth.passwordRealm(), auth.createUser(),
auth.resetPassword(), and MFA Flexible Factors Grant, and either remove the web
support claim or adjust the matrix so both docs match the same
supported/unsupported status.
- Around line 179-205: The MFA example in the documentation is logging sensitive
credentials, so update the example flow in the mfa enrollment and verification
snippets to stop printing the TOTP secret and access token to the console. Keep
the surrounding MfaError handling and the enrollTotp/verifyOtp examples intact,
but replace the console output in the challenge.type === 'totp' and successful
verify paths with non-sensitive guidance or remove those logs entirely.
In `@EXAMPLES.md`:
- Around line 1818-1820: The sample MFA logging in EXAMPLES.md is printing
sensitive values, so update the affected example blocks to avoid outputting
secrets, codes, or tokens. In the challenge-handling examples (including the
code paths that reference challenge.secret, oobCode, and accessToken), replace
the current console.log statements with redacted or generic status messages that
confirm progress without exposing credentials. Use the relevant example sections
around the MFA challenge flows to locate and update all affected snippets.
In `@ios/A0MfaClient.swift`:
- Around line 77-95: The `.voice` case in `A0MfaClient.enroll` is currently
sharing the same `enroll(mfaToken:phoneNumber:)` path as `.phone`, which drops
the channel distinction for iOS. Update the `switch factorType` handling so
`voice` is either routed through a voice-specific native enrollment path in
`mfaClient` or explicitly rejected as unsupported, while keeping `.phone` on the
SMS/phone-number flow. Use the existing `factorType` switch and
`mfaClient.enroll` call site to locate the change.
In `@src/core/models/__tests__/ErrorCodes.spec.ts`:
- Around line 257-265: The overlap checks in ErrorCodes.spec use `includes(code
as any)`, which hides a type mismatch with the literal arrays. Update the test
data types so `webAuthArray`, `credentialsArray`, and `dpopArray` are typed
compatibly (for example as `string[]` or a shared string union) and then call
`includes` without `as any` in the `mfaArray.filter` checks. Keep the fix local
to the overlap test block and preserve the existing `webAuthOverlaps`,
`credentialsOverlaps`, and `dpopOverlaps` assertions.
In `@src/core/models/MfaError.ts`:
- Around line 70-99: The `ERROR_CODE_MAP` in `MfaError` is mapping the generic
`invalid_grant` response directly to `MfaErrorCodes.INVALID_OTP`, which can
misclassify expired or invalid MFA tokens. Update the MFA error parsing logic in
`MfaError` so `invalid_grant` is not blindly normalized in the same way for all
flows; inspect the accompanying `error_description` or parsed JSON/error payload
first, then map token-expiry or token-invalid cases to `EXPIRED_MFA_TOKEN` or
`INVALID_MFA_TOKEN`, and only fall back to `INVALID_OTP` when the response
clearly indicates an OTP failure.
In `@src/factory/Auth0ClientFactory.web.ts`:
- Line 26: The web SPA client singleton in WebAuth0Client.getSpaClient() is
still shared across all configs, so a new Auth0ClientFactory.web.ts signature
can still end up reusing the first Auth0Client. Update the singleton handling in
WebAuth0Client and its getSpaClient() path so it is keyed by the same config
signature used by getConfigSignature(options), or reset/recreate the cached
spa-js client whenever the signature changes. Make sure the cache invalidation
logic is tied to the existing Auth0ClientFactory.web.ts singleton flow so
tenant/config switching returns the correct Auth0Client.
In `@src/hooks/Auth0Provider.tsx`:
- Around line 52-58: Reset the auth state when the tenant signature changes in
Auth0Provider so the old client’s user/error do not persist while the new Auth0
instance initializes. Update the state management around the reducer and the
initialization effect tied to configSignature to clear the current user and
error and set loading true before starting the new client setup. Use the
Auth0Provider, getConfigSignature, and the async initialization effect that
follows the useMemo client creation as the places to apply the reset.
In `@src/platforms/native/adapters/__tests__/NativeMfaClient.spec.ts`:
- Around line 5-27: The `mockBridge` declaration in `NativeMfaClient.spec` is
too strongly typed for the subset of `INativeBridge` methods it actually
provides, which breaks strict TypeScript compilation. Update the test mock to
use a partial/selected type instead of `jest.Mocked<INativeBridge>`, keeping
only the methods exercised by the MFA tests (and any already-used helpers) while
preserving proper Jest mocks. Use the `INativeBridge` interface and the
`mockBridge` constant as the key references when adjusting the type.
In `@src/platforms/native/adapters/NativeAuth0Client.ts`:
- Around line 141-145: The native config refresh in NativeAuth0Client is only
protected by an instance-level syncLock, so sibling clients can still interleave
initialize() and the subsequent bridge call and run against the wrong tenant
config. Update the shared native access path in NativeAuth0Client so the re-sync
and the original bridge invocation are serialized with a process-wide guard, and
make sure the direct getDPoPHeaders flow uses the same protection instead of
bypassing syncNativeConfig().
---
Outside diff comments:
In `@android/src/main/oldarch/com/auth0/react/A0Auth0Spec.kt`:
- Around line 204-209: The Android old-architecture bridge method
passkeyEnrollmentChallenge in A0Auth0Spec is missing the annotations needed for
export. Add back the React Native bridge annotations on this abstract method so
it remains discoverable from JS, using the same pattern as the other bridged
methods in A0Auth0Spec, specifically `@ReactMethod` and `@DoNotStrip`.
---
Nitpick comments:
In `@src/core/models/MfaError.ts`:
- Line 70: Strengthen the typing in MfaError by replacing the broad string-based
declarations for ERROR_CODE_MAP and the error type with the literal union
derived from MfaErrorCodes, so consumers keep type-safe comparisons like e.type
=== MfaErrorCodes.INVALID_OTP. Update the MfaError class and any related
constructor/field typings in the MfaError implementation to use the inferred
value type from MfaErrorCodes instead of string, and make sure the map preserves
the existing enum-like literals throughout the code paths referenced by
MfaErrorCodes and MfaError.
In `@src/platforms/native/adapters/NativeMfaClient.ts`:
- Around line 21-108: The exported NativeMfaClient adapter is public but its API
is undocumented; add JSDoc to the class and each public method (constructor,
getAuthenticators, enroll, challenge, and verify) so the MFA bridge contract is
discoverable and matches the documentation style used across src/**/*.ts.
Include brief descriptions of each method’s purpose, parameters, and return
values, and keep the docs aligned with the existing IMfaClient/INativeBridge
terminology to make the adapter surface consistent.
In `@src/platforms/web/adapters/WebMfaClient.ts`:
- Around line 44-46: The WebMfaClient.getAuthenticators path is dropping the
optional factorsAllowed filter because only parameters.mfaToken is passed into
spaMfa.getAuthenticators. Update WebMfaClient so it either forwards or applies
parameters.factorsAllowed before returning authenticators, using the existing
MfaGetAuthenticatorsParameters and getAuthenticators symbols to locate the
change. If filtering cannot be supported on web, make that behavior explicit
instead of silently ignoring it.
- Around line 73-76: Avoid using any for the spa request payloads in
WebMfaClient by replacing spaParams with the appropriate spa-js parameter type
or a strict local discriminated union so TypeScript can validate the request
shape. Update the mfaToken/factorType payload construction in the affected
WebMfaClient methods (including the other matching spaParams assignment) to use
concrete typing and keep the payload compatible with the spa-js request APIs.
In `@src/types/parameters.ts`:
- Around line 286-288: The MfaGetAuthenticatorsParameters type is using a loose
string[] for factorsAllowed, which drops the factor discriminant typing used
elsewhere. Update factorsAllowed in MfaGetAuthenticatorsParameters to use
MfaFactorType[] (or the existing literal union type if that is the canonical
form) so callers get autocomplete and type safety, and make sure any related
references in this file stay consistent with the MFA factor type definitions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e1e08998-d3c8-4f45-bcbf-c3e1fd415f0e
⛔ Files ignored due to path filters (4)
example/Gemfile.lockis excluded by!**/*.lockexample/ios/Podfile.lockis excluded by!**/*.locksrc/plugin/__tests__/__snapshots__/withAuth0-test.ts.snapis excluded by!**/*.snapyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (53)
.github/workflows/release.ymlA0Auth0.podspecCHANGELOG.mdEXAMPLES-WEB.mdEXAMPLES.mdREADME.mdandroid/src/main/java/com/auth0/react/A0Auth0Module.ktandroid/src/main/java/com/auth0/react/MfaClient.ktandroid/src/main/oldarch/com/auth0/react/A0Auth0Spec.ktexample/Gemfileexample/android/gradle/wrapper/gradle-wrapper.propertiesexample/android/gradlewexample/android/gradlew.batexample/ios/Auth0Example.xcodeproj/project.pbxprojexample/package.jsonexample/src/App.web.tsxexample/src/screens/class-based/ClassApiTests.tsxexample/src/screens/class-based/ClassLogin.tsxexample/src/screens/hooks/Home.tsxios/A0Auth0.mmios/A0MfaClient.swiftios/NativeBridge.swiftpackage.jsonsrc/Auth0.tssrc/core/interfaces/IAuth0Client.tssrc/core/interfaces/IMfaClient.tssrc/core/interfaces/index.tssrc/core/models/MfaError.tssrc/core/models/__tests__/ErrorCodes.spec.tssrc/core/models/__tests__/MfaError.spec.tssrc/core/models/index.tssrc/core/utils/__tests__/configSignature.spec.tssrc/core/utils/configSignature.tssrc/core/utils/index.tssrc/factory/Auth0ClientFactory.tssrc/factory/Auth0ClientFactory.web.tssrc/factory/__tests__/Auth0ClientFactory.spec.tssrc/hooks/Auth0Context.tssrc/hooks/Auth0Provider.tsxsrc/index.tssrc/platforms/native/adapters/NativeAuth0Client.tssrc/platforms/native/adapters/NativeMfaClient.tssrc/platforms/native/adapters/__tests__/NativeAuth0Client.spec.tssrc/platforms/native/adapters/__tests__/NativeMfaClient.spec.tssrc/platforms/native/adapters/index.tssrc/platforms/native/bridge/INativeBridge.tssrc/platforms/native/bridge/NativeBridgeManager.tssrc/platforms/web/adapters/WebAuth0Client.tssrc/platforms/web/adapters/WebMfaClient.tssrc/platforms/web/adapters/index.tssrc/specs/NativeA0Auth0.tssrc/types/common.tssrc/types/parameters.ts
💤 Files with no reviewable changes (1)
- example/android/gradlew
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
🛑 Comments failed to post (17)
android/src/main/java/com/auth0/react/MfaClient.kt (1)
58-68: 🎯 Functional Correctness | 🟠 Major
🧩 Analysis chain
🌐 Web query:
Auth0 Android SDK 3.19.0 MfaEnrollmentType voice MFA enrollment supported value💡 Result:
In the Auth0 Android SDK (including version 3.19.0), the MfaEnrollmentType class is used to specify the type of MFA factor for enrollment [1][2]. While the SDK supports phone-based MFA, it does not have a distinct MfaEnrollmentType value specifically named "voice" [1][2]. Instead, you use MfaEnrollmentType.Phone(phoneNumber: String) to initiate enrollment for phone-based factors [1][2]. The Auth0 API handles SMS and voice as channels for this factor [3][4]. When enrolling or challenging via the API, the channel is typically distinguished by the oob_channels parameter, where you specify "sms" or "voice" [3]. In the context of the Android SDK's MfaClient, the Phone type is designed to collect the phone number [1][2]. If you need to specify a preference for voice, you may need to ensure your backend or Auth0 tenant configuration is set to support voice as an OOB (Out-of-Band) channel, as the mobile SDK interfaces generally abstract these as phone enrollments [3][4]. Top results: [1] https://github.com/auth0/Auth0.Android/blob/main/EXAMPLES.md [3] https://auth0.com/docs/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators [2] https://github.com/auth0/Auth0.android/blob/main/EXAMPLES.md [4] https://auth0.com/docs/secure/multi-factor-authentication/manage-mfa-auth0-apis/manage-authenticator-factors-mfa-api
Citations:
- 1: https://github.com/auth0/Auth0.Android/blob/main/EXAMPLES.md
- 2: https://github.com/auth0/auth0.android/blob/main/EXAMPLES.md
- 3: https://auth0.com/docs/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators
- 4: https://auth0.com/docs/secure/multi-factor-authentication/manage-mfa-auth0-apis/manage-authenticator-factors-mfa-api
🏁 Script executed:
#!/bin/bash set -euo pipefail # Map the target file and read the relevant sections with line numbers. wc -l android/src/main/java/com/auth0/react/MfaClient.kt sed -n '1,220p' android/src/main/java/com/auth0/react/MfaClient.kt | cat -n # Find related MFA factor/type usage in the Android bridge. rg -n "MfaFactorType|MfaEnrollmentType|voice|push-notification|recovery-code|mapFactorType|mapEnrollment" android/src/main/java -SRepository: auth0/react-native-auth0
Length of output: 13148
🏁 Script executed:
#!/bin/bash set -euo pipefail # Inspect the Auth0 Android SDK API references in the repo, if vendored or documented here. rg -n "class MfaEnrollmentType|object MfaEnrollmentType|sealed class MfaEnrollmentType|enum class MfaFactorType|voice" -S .Repository: auth0/react-native-auth0
Length of output: 2387
🏁 Script executed:
#!/bin/bash set -euo pipefail # Inspect any nearby tests or docs that describe MFA factor mapping behavior. rg -n "mapFactorType|mapEnrollment|phone|sms|voice|MfaClient" android -SRepository: auth0/react-native-auth0
Length of output: 2899
🏁 Script executed:
#!/bin/bash set -euo pipefail sed -n '1,220p' android/src/main/java/com/auth0/react/MfaClient.kt | cat -nRepository: auth0/react-native-auth0
Length of output: 10589
🏁 Script executed:
#!/bin/bash set -euo pipefail # Inspect JS-facing MFA parameter docs and native adapters for voice handling. sed -n '300,360p' src/types/parameters.ts | cat -n sed -n '40,95p' src/platforms/native/adapters/NativeMfaClient.ts | cat -n sed -n '75,95p' src/platforms/web/adapters/WebMfaClient.ts | cat -n sed -n '70,95p' ios/A0MfaClient.swift | cat -nRepository: auth0/react-native-auth0
Length of output: 6179
🏁 Script executed:
#!/bin/bash set -euo pipefail # Read the nearby README/Examples snippets that describe voice MFA enrollment/challenge. rg -n -A8 -B4 "voice" README.md EXAMPLES.md src/types/parameters.ts src/platforms/native/adapters/NativeMfaClient.ts ios/A0MfaClient.swiftRepository: auth0/react-native-auth0
Length of output: 9334
🏁 Script executed:
#!/bin/bash set -euo pipefail # Inspect the iOS voice factor mapping and any Android factor-list/filter usage for comparison. sed -n '1,140p' ios/A0MfaClient.swift | cat -n rg -n "getAuthenticators|mapFactorType|MfaFactorType|voice" android/src/main/java/com/auth0/react -SRepository: auth0/react-native-auth0
Length of output: 8709
🌐 Web query:
Auth0 Android MFA getAuthenticators voice sms factor type oob_channels phone voice💡 Result:
In the Auth0 ecosystem, including for Android, SMS and Voice are categorized as Out-of-Band (OOB) authentication factors [1][2]. When interacting with the Auth0 MFA API (such as when using the Resource Owner Password Grant), these factors are handled as follows: 1. Factor Type: The
authenticator_typeis identified asoob[1][3]. 2. OOB Channels: The specific delivery method is distinguished by theoob_channelparameter, which accepts values of eithersmsorvoice[3][4][2]. When enrolling a user for phone-based MFA via the API, you must specify both the type and the channel [3][2]. For example, when calling the /mfa/associate endpoint, you would provide: - authenticator_types: ["oob"] [4][2] - oob_channels: ["sms"] or ["voice"] [4][2] Auth0 treats SMS and Voice as distinct authenticators for the same phone number [1]. If both are enabled for a user, enrolling in one may automatically create authenticators for both, and deleting one may remove the other [1]. In the Auth0.Android SDK, you should utilize the MfaApiClient class for managing these interactions, as legacy authentication methods are deprecated [5][6]. The SDK requires that the MFA grant type is enabled in your application's Advanced Settings in the Auth0 Dashboard [7][8]. Note that while the SDK facilitates these flows, your application must provide the user interface to collect the phone number, prompt for the binding code (the OTP sent via SMS/Voice), and handle the authentication challenge [3][7][9].Citations:
- 1: https://auth0.com/docs/secure/multi-factor-authentication/manage-mfa-auth0-apis/manage-authenticator-factors-mfa-api
- 2: https://github.com/auth0/docs/blob/master/articles/api/authentication/_multifactor-authentication.md
- 3: https://auth0.com/docs/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators
- 4: https://auth0.mintlify.app/docs/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators
- 5: https://javadoc.io/static/com.auth0.android/auth0/3.7.0/auth0/com.auth0.android.authentication/-authentication-a-p-i-client/index.html
- 6: https://github.com/auth0/Auth0.Android/blob/main/auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.kt
- 7: https://github.com/auth0/Auth0.Android/blob/3.10.0/EXAMPLES.md
- 8: https://auth0.com/docs/secure/multi-factor-authentication/multi-factor-authentication-developer-resources/mfa-api
- 9: https://sus.auth0.com/docs/secure/multi-factor-authentication/multi-factor-authentication-factors/configure-sms-voice-notifications-mfa
🌐 Web query:
Auth0 MFA factors allowed voice sms phone getAuthenticators factor type oob_channels💡 Result:
In Auth0's Multi-Factor Authentication (MFA) system, SMS and voice are supported factors [1][2]. When interacting with the Auth0 Authentication API, specifically the MFA endpoints (such as
getAuthenticators), these phone-based factors are categorized under theoob(Out-of-Band) authenticator type [3][4][5]. When a user is enrolled in SMS or voice, their authenticator record in the API response includes anoob_channelfield that specifies the delivery method, which can besmsorvoice[3][4][5]. Key details regarding these factors include: - OOB Channels: Theoob_channelsparameter, used during enrollment or identification in the Authentication API, accepts the valuessmsorvoiceto determine how the MFA code is delivered [4][5]. - Automatic Enrollment: If both SMS and voice are enabled for a user, enrolling a phone number typically results in Auth0 creating two separate authenticator entries for that number—one for SMS and one for voice [3]. - Deletion Behavior: Because these entries are linked to the same phone number, deleting either the SMS or voice authenticator will automatically delete the other [3]. - API Usage: To list enrolled factors, you use theGET /mfa/authenticatorsendpoint [3][6]. When enrolling or challenging these factors, you must specify theauthentication_typesas[oob]and theoob_channelsas either[sms]or[voice][4][5]. For comprehensive management, Auth0 documentation differentiates between independent factors (such as Phone Message, which covers SMS/Voice) and dependent factors [7]. SMS and voice configurations can be managed through the Auth0 Dashboard or the Management API's/api/v2/guardian/factors/phone/message-typesendpoint, which supports settingmessage_typesto["sms"],["voice"], or both [8].Citations:
- 1: https://auth0.com/docs/secure/multi-factor-authentication/multi-factor-authentication-factors
- 2: https://auth0.com/docs/secure/multi-factor-authentication
- 3: https://auth0.com/docs/secure/multi-factor-authentication/manage-mfa-auth0-apis/manage-authenticator-factors-mfa-api
- 4: https://auth0.com/docs/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators
- 5: https://github.com/auth0/docs/blob/master/articles/api/authentication/_multifactor-authentication.md
- 6: https://auth0.mintlify.app/docs/api/authentication/muti-factor-authentication/list-authenticators
- 7: https://auth0.com/docs/secure/multi-factor-authentication/enable-mfa
- 8: https://auth0.com/docs/secure/multi-factor-authentication/multi-factor-authentication-factors/configure-sms-voice-notifications-mfa
🏁 Script executed:
#!/bin/bash set -euo pipefail sed -n '1,120p' src/platforms/native/adapters/NativeMfaClient.ts | cat -nRepository: auth0/react-native-auth0
Length of output: 3884
🏁 Script executed:
#!/bin/bash set -euo pipefail rg -n "getAuthenticators|factorsAllowed|factorType === 'sms'|factorType === 'voice'|voice" src/platforms/native/adapters/NativeMfaClient.ts src/platforms/web/adapters/WebMfaClient.ts src/types/parameters.ts -SRepository: auth0/react-native-auth0
Length of output: 1210
🏁 Script executed:
#!/bin/bash set -euo pipefail # Inspect the JS type definitions and bridge contract for MFA authenticators/factors. sed -n '260,310p' src/types/parameters.ts | cat -n sed -n '1,140p' src/platforms/native/bridge.ts | cat -n sed -n '1,120p' src/platforms/web/adapters/WebMfaClient.ts | cat -nRepository: auth0/react-native-auth0
Length of output: 1883
🏁 Script executed:
#!/bin/bash set -euo pipefail rg -n -A12 -B6 "getAuthenticators\\(" src/platforms/web/adapters/WebMfaClient.ts src/platforms/native/adapters/NativeMfaClient.ts src/types/parameters.ts -SRepository: auth0/react-native-auth0
Length of output: 3482
🏁 Script executed:
#!/bin/bash set -euo pipefail rg -n "getMfaAuthenticators|mfaEnroll\\(|mfaChallenge\\(|mfaVerify\\(" src/platforms/native -SRepository: auth0/react-native-auth0
Length of output: 2524
🏁 Script executed:
#!/bin/bash set -euo pipefail sed -n '220,320p' src/platforms/native/bridge/INativeBridge.ts | cat -n sed -n '260,320p' src/platforms/native/bridge/NativeBridgeManager.ts | cat -n sed -n '1,220p' android/src/main/java/com/auth0/react/A0Auth0Module.kt | cat -n | sed -n '630,720p'Repository: auth0/react-native-auth0
Length of output: 6142
🏁 Script executed:
#!/bin/bash set -euo pipefail rg -n -A25 -B10 "getMfaAuthenticators|mfaEnroll|mfaChallenge|mfaVerify" android/src/main/java/com/auth0/react/A0Auth0Module.kt android/src/main/java/com/auth0/react/MfaClient.kt -SRepository: auth0/react-native-auth0
Length of output: 5203
🌐 Web query:
Auth0 Android MfaClient getAuthenticators factorsAllowed sms voice authenticatorType oobChannel💡 Result:
In the Auth0 Android SDK, the
MfaApiClientis used to handle multi-factor authentication (MFA) flows, including retrieving available authenticators [1][2]. ThegetAuthenticatorsmethod allows you to fetch a list of authenticators enrolled for a user that are valid for the current MFA challenge [1]. You can use thefactorsAllowedparameter to filter these results by providing a list of accepted factor types [1]. Key details regarding the factors and types include: 1. FactorsAllowed: This parameter expects a list of strings representing the MFA factor types, such as "otp", "sms", "voice", or "push" [1][2]. These types are typically extracted from themfaRequirementspayload returned when an authentication attempt fails with anmfa_requirederror [2]. 2. Authenticator Types and OOB Channels: - When an authenticator has the type "oob" (Out-of-Band), it uses anoob_channelto deliver the challenge [3][4]. - Common values foroob_channelinclude "sms" and "voice" [3][4]. - When a user enrolls a phone number for SMS or voice, Auth0 may create separate authenticator entries for each if both are enabled [3]. - When triggering a challenge for an OOB factor, theoobCodeandbindingCodeare typically required for verification [1]. For implementation, ensure your application has the "MFA" grant type enabled in your Auth0 application settings [2][5]. The flow generally involves: - Capturing themfa_requiredexception during login [2]. - Extracting themfaTokenand availablechallengetypes from the error payload [2]. - CallingmfaClient.getAuthenticators(factorsAllowed = challengeTypes)[1]. - Initiating a challenge withmfaClient.challenge(authenticatorId = ...)[1]. - Verifying the user's input withmfaClient.verify(...)[1]. For complex UI requirements, consider using theauth0-ui-components-androidlibrary, which provides pre-built Jetpack Compose components for managing MFA enrollment and verification [6].Citations:
- 1: https://context7.com/auth0/auth0.android/llms.txt
- 2: https://github.com/auth0/Auth0.Android/blob/main/EXAMPLES.md
- 3: https://auth0.com/docs/secure/multi-factor-authentication/manage-mfa-auth0-apis/manage-authenticator-factors-mfa-api
- 4: https://auth0.mintlify.app/docs/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators
- 5: https://github.com/auth0/Auth0.Android/blob/3.10.0/EXAMPLES.md
- 6: https://github.com/auth0/ui-components-android
🌐 Web query:
site:github.com/auth0/Auth0.Android getAuthenticators factorsAllowed voice sms MfaClient💡 Result:
In the Auth0 Android SDK, the MfaClient.getAuthenticators method is used during the multi-factor authentication (MFA) challenge flow to retrieve a list of authenticators that a user has previously enrolled [1]. The factorsAllowed parameter is an optional list (in Kotlin, a List) that filters the retrieved authenticators to include only those that match the allowed factor types specified by your application's MFA requirements [2][1]. When you receive an mfa_required error during authentication, the error payload contains specific requirements, including which factors (e.g., 'sms', 'voice', or 'otp') are permitted for the current authentication attempt [3][1]. You map these required types to a list and pass them to getAuthenticators to ensure the user is only presented with appropriate options [2][1]. Example usage in Kotlin: val factorTypes = listOf("sms", "voice") // Map from mfaRequirements mfaClient.getAuthenticators(factorsAllowed = factorTypes).start(object: Callback<List, MfaListAuthenticatorsException> { override fun onSuccess(authenticators: List) { // Display authenticators for user to choose } override fun onFailure(exception: MfaListAuthenticatorsException) { // Handle error } }) If you are using Java, you must provide an ArrayList for the factorsAllowed parameter [1]. This API is part of the modern MfaApiClient, which replaced deprecated MFA methods in the AuthenticationAPIClient [4][5].
Citations:
- 1: https://github.com/auth0/auth0.android/blob/main/EXAMPLES.md
- 2: https://github.com/auth0/Auth0.Android/blob/main/EXAMPLES.md
- 3: https://github.com/auth0/Auth0.Android/blob/main/auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.kt
- 4: auth0/Auth0.Android@18d763a
- 5: https://github.com/auth0/Auth0.Android/releases/tag/3.14.0
🏁 Script executed:
#!/bin/bash set -euo pipefail sed -n '1,180p' src/platforms/native/adapters/__tests__/NativeMfaClient.spec.ts | cat -nRepository: auth0/react-native-auth0
Length of output: 6850
🏁 Script executed:
#!/bin/bash set -euo pipefail # Inspect MFA types/tests for how factorsAllowed and voice are intended to flow. sed -n '1,120p' src/platforms/native/adapters/__tests__/NativeMfaClient.spec.ts | cat -n sed -n '1,120p' src/types/parameters.ts | cat -n sed -n '1,120p' src/types/common.ts | cat -nRepository: auth0/react-native-auth0
Length of output: 14237
🏁 Script executed:
#!/bin/bash set -euo pipefail rg -n -A6 -B6 "factorsAllowed|voice|sms|oob|getAuthenticators" src/platforms/native/adapters/__tests__ src/types src/platforms/native -SRepository: auth0/react-native-auth0
Length of output: 50382
🌐 Web query:
Auth0.Android getAuthenticators factors list voice sms oob authenticatorType oobChannel docs💡 Result:
In the Auth0.Android SDK and associated Auth0 MFA APIs, authentication factors are categorized by their type, which determines how a user proves possession [1][2]. The primary
authenticator_typevalues relevant to your query areotp(One-Time Password) andoob(Out-of-Band) [1][3][2]. When theauthenticator_typeis set tooob, you must specify theoob_channelparameter to define the delivery mechanism for the verification challenge [4][3]. The supportedoob_channelvalues for phone-based MFA are: - sms: Sends a one-time code via SMS [4][5]. - voice: Sends a one-time code via a voice call [4][5]. To manage these factors programmatically—such as enrolling a new factor or requesting a challenge—you interact with the Auth0 Authentication API [1][6]. For example, when associating an MFA authenticator, you provide theauthenticator_types(e.g.,["oob"]) and the correspondingoob_channels(e.g.,["sms"]or["voice"]) [4][3]. While theAuthenticationAPIClientin the Android SDK provides methods to request MFA challenges, it is recommended to check the specific implementation in your version of the SDK [1][2]. Some older methods in the SDK are deprecated in favor of newer API patterns [1]. Always refer to the official Auth0 documentation for the most current handling of MFA flows, as configurations may vary based on your tenant's specific MFA settings and subscription plan [4][5][7].Citations:
- 1: https://github.com/auth0/Auth0.Android/blob/main/auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.kt
- 2: https://javadoc.io/static/com.auth0.android/auth0/3.7.0/auth0/com.auth0.android.authentication/-authentication-a-p-i-client/index.html
- 3: https://auth0.github.io/auth0.net/api/Auth0.AuthenticationApi.Models.Mfa.AssociateMfaAuthenticatorRequest.html
- 4: https://auth0.com/docs/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators
- 5: https://auth0.com/docs/secure/multi-factor-authentication/multi-factor-authentication-factors/configure-sms-voice-notifications-mfa
- 6: https://auth0.com/docs/secure/multi-factor-authentication/multi-factor-authentication-developer-resources
- 7: https://auth0.com/docs/secure/multi-factor-authentication/multi-factor-authentication-factors
🌐 Web query:
Auth0.Android MfaEnrollmentType.Phone voice sms oob channel docs💡 Result:
In the context of Auth0 and the Auth0.Android SDK, multi-factor authentication (MFA) involving phone numbers is handled through the "oob" (Out-of-Band) authenticator type [1][2]. 1. MFA Factors and Channels The "oob" (Out-of-Band) authenticator type is used for MFA challenges that occur outside the primary authentication channel, such as SMS or voice phone calls [1][2]. When enrolling a phone number, the
oob_channelsparameter identifies the specific method used to send the verification code, with accepted values being "sms" or "voice" [1]. 2. Auth0.Android SDK Implementation The Auth0.Android SDK provides dedicated methods to enroll and manage these phone-based factors [3]. Specifically, you can use theenrollPhonemethod, which requires the user's phone number and aPhoneAuthenticationMethodTypeto specify the channel (e.g.,PhoneAuthenticationMethodType.SMS) [3]. Example (Kotlin): myAccountClient.enrollPhone("+11234567890", PhoneAuthenticationMethodType.SMS).start(object: Callback<EnrollmentChallenge, MyAccountException> { override fun onSuccess(result: EnrollmentChallenge) { // OTP sent. Use result.id and result.authSession to verify. } override fun onFailure(error: MyAccountException) { } }) 3. Key Concepts * Authenticator Type: Set to "oob" when performing MFA via SMS or Voice [1][4]. * OOB Channel: Specifies the delivery mechanism ("sms" or "voice") [1]. * Enrollment Flow: This is typically a two-step process: first, you request an enrollment challenge (which triggers the code delivery), and second, you verify that challenge using the code received by the user [3]. For additional context, Auth0 also supports "push" notifications and "otp" (one-time password) as distinct MFA factors, which are managed differently than the phone-based OOB channels [5][6]. Always ensure the MFA grant type is enabled in your Auth0 Dashboard application settings before attempting to use these flows [3][7].Citations:
- 1: https://auth0.com/docs/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators
- 2: https://auth0.com/docs/api/authentication/multi-factor-authentication/verify-with-out-of-band
- 3: https://github.com/auth0/Auth0.Android/blob/3.10.0/EXAMPLES.md
- 4: https://github.com/auth0/Auth0.Android/blob/main/auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.kt
- 5: https://auth0.com/docs/secure/multi-factor-authentication/manage-mfa-auth0-apis/manage-authenticator-factors-mfa-api
- 6: https://auth0.com/docs/secure/multi-factor-authentication/auth0-guardian/guardian-for-android-sdk
- 7: https://auth0.com/docs/libraries/auth0-android/auth0-android-passwordless
🌐 Web query:
site:auth0.com docs Auth0 Android MfaEnrollmentType.Phone sms voice phone enrollment💡 Result:
In Auth0 development, SMS and voice MFA are categorized as phone-based authenticators. While there is no specific
MfaEnrollmentType.Phoneconstant in the standard Auth0.Android library, these factors are handled via the Auth0 Universal Login flow or the MFA API using theoob(Out-of-Band) authenticator type [1][2]. When implementing MFA enrollment for phone-based methods: 1. Identification: SMS and voice are treated as separate delivery channels (often referred to asoob_channelsin API contexts) [1][3]. 2. Implementation: - Universal Login: Auth0 handles the MFA enrollment UI automatically. If configured, users can choose between SMS or voice delivery methods when enrolling their phone number [4][5][3]. - Custom Flows: If you are building a custom UI, you must interact with the MFA API [2]. When enrolling, you submit the phone number and specify theoob_channelsas eithersmsorvoice[1][3]. 3. Data Handling: If both SMS and voice are enabled, Auth0 will automatically create two distinct authenticators for the same phone number (one for each method) upon enrollment [2]. For Android-specific applications, the recommended approach is to use the Universal Login experience via theWebAuthProviderin theauth0-androidSDK, which manages these MFA transitions natively without requiring custom enrollment logic for individual factors [6]. If you are working with specialized push-notification-based MFA, theGuardianSDK for Android is used instead for device-bound enrollments [7].Citations:
- 1: https://auth0.com/docs/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators
- 2: https://auth0.com/docs/secure/multi-factor-authentication/manage-mfa-auth0-apis/manage-authenticator-factors-mfa-api
- 3: https://auth0.com/docs/secure/multi-factor-authentication/multi-factor-authentication-factors/configure-sms-voice-notifications-mfa
- 4: https://auth0.com/docs/libraries/acul/react-sdk/API-Reference/Screens/mfa-phone-enrollment
- 5: https://auth0.com/docs/libraries/acul/js-sdk/Screens/classes/MfaPhoneEnrollment
- 6: https://auth0.com/docs/libraries/auth0-android
- 7: https://auth0.com/docs/secure/multi-factor-authentication/auth0-guardian/guardian-for-android-sdk
🏁 Script executed:
#!/bin/bash set -euo pipefail rg -n -A4 -B4 "voice" android README.md EXAMPLES.md src/platforms/native/adapters/__tests__/NativeMfaClient.spec.ts src/types/parameters.ts -SRepository: auth0/react-native-auth0
Length of output: 12151
Don't map
voicetosmsinmapFactorType().factorsAllowedcan includevoice, and collapsing it tosmsmakesgetAuthenticators()return SMS authenticators for voice-only flows.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@android/src/main/java/com/auth0/react/MfaClient.kt` around lines 58 - 68, The factor normalization in mapFactorType() is incorrectly collapsing voice into sms, which causes voice-only options to be exposed as SMS authenticators. Update mapFactorType() in MfaClient to preserve voice as its own factor instead of mapping it to sms, while keeping the existing mappings for otp, sms, email, push, oob, and recovery-code unchanged.example/src/App.web.tsx (1)
453-456: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Don’t send TOTP enrollment secrets to a third-party QR service.
barcodeUricontains the TOTP secret; embedding it inhttps://api.qrserver.com/...leaks that secret off-device. Use an in-app/local QR renderer or omit the QR image and show only the deep link/secret.Also applies to: 1032-1035
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@example/src/App.web.tsx` around lines 453 - 456, The QR image generation in the App.web.tsx TOTP enrollment flow is leaking the secret by sending enrollmentChallenge.barcodeUri to a third-party service. Update the Image usage in the enrollment UI to avoid remote QR generation: use a local/in-app QR renderer or remove the QR image entirely and present only the deep link/secret, and apply the same change anywhere else the same pattern appears in the enrollment screen.example/src/screens/class-based/ClassApiTests.tsx (2)
153-153: 🎯 Functional Correctness | 🔴 Critical
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash rg -n "interface IMfaClient|type MfaEnroll|interface MfaEnroll|factorType|\\.enroll\\(" src example -C 3Repository: auth0/react-native-auth0
Length of output: 21896
🏁 Script executed:
#!/bin/bash set -euo pipefail # Inspect the relevant screen and the helper used by the test buttons. sed -n '1,260p' example/src/screens/class-based/ClassApiTests.tsx printf '\n--- runTest search ---\n' rg -n "function runTest|const runTest|runTest\\(" example/src/screens/class-based/ClassApiTests.tsx example/src -C 3 printf '\n--- IMfaClient contract ---\n' sed -n '1,220p' src/core/interfaces/IMfaClient.tsRepository: auth0/react-native-auth0
Length of output: 33959
🏁 Script executed:
#!/bin/bash set -euo pipefail # Inspect the relevant screen and the helper used by the test buttons. sed -n '1,260p' example/src/screens/class-based/ClassApiTests.tsx printf '\n--- runTest search ---\n' rg -n "function runTest|const runTest|runTest\\(" example/src/screens/class-based/ClassApiTests.tsx example/src -C 3 printf '\n--- IMfaClient contract ---\n' sed -n '1,220p' src/core/interfaces/IMfaClient.tsRepository: auth0/react-native-auth0
Length of output: 33959
🏁 Script executed:
#!/bin/bash set -euo pipefail # Check what MFA verify returns and whether it contains credential material. sed -n '1,220p' src/types/common.ts printf '\n--- MfaVerifyParameters ---\n' sed -n '220,340p' src/types/parameters.tsRepository: auth0/react-native-auth0
Length of output: 10921
🏁 Script executed:
#!/bin/bash set -euo pipefail # Check what MFA verify returns and whether it contains credential material. sed -n '1,220p' src/types/common.ts printf '\n--- MfaVerifyParameters ---\n' sed -n '220,340p' src/types/parameters.tsRepository: auth0/react-native-auth0
Length of output: 10921
Use
factorTypefor MFA enrollment.
IMfaClient.enrollexpectsfactorType;typedoes not match the contract and will fail type-checking.- The nearby
mfa().verify()call returns credentials, so routing it throughrunTestexposes tokens in the console/UI.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@example/src/screens/class-based/ClassApiTests.tsx` at line 153, The MFA enrollment call in ClassApiTests is using the wrong property name and the verification flow is leaking returned credentials through runTest. Update the auth0.mfa().enroll invocation to use factorType instead of type, and adjust the nearby mfa().verify path so it is not wrapped in runTest when it returns credentials; keep the tokens out of console/UI exposure by handling that result internally in the test helper or directly awaiting it.
182-185: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Redact credentials returned by MFA verification before logging/rendering.
runTestlogs and displays the raw result, somfa().verify()can expose access, ID, or refresh tokens. Return a sanitized summary instead. As per coding guidelines, “Never log access tokens, refresh tokens, or ID tokens in error messages or debug output.”Proposed fix
- runTest(() => auth0.mfa().verify({ mfaToken, otp }), 'Verify OTP') + runTest(async () => { + const credentials = await auth0.mfa().verify({ mfaToken, otp }); + return { + success: true, + tokenType: credentials.tokenType, + expiresAt: credentials.expiresAt, + }; + }, 'Verify OTP')📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.<Button onPress={() => runTest(async () => { const credentials = await auth0.mfa().verify({ mfaToken, otp }); return { success: true, tokenType: credentials.tokenType, expiresAt: credentials.expiresAt, }; }, 'Verify OTP') }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@example/src/screens/class-based/ClassApiTests.tsx` around lines 182 - 185, The MFA verification flow in ClassApiTests and the runTest helper is exposing raw credential-bearing results from auth0.mfa().verify(), which can leak sensitive tokens into logs and UI. Update the Verify OTP path to sanitize the returned value before passing it to runTest, and ensure runTest only logs/displays a redacted summary rather than the full verification response. Use the auth0.mfa().verify call site and runTest as the key places to apply the redaction.Source: Coding guidelines
example/src/screens/class-based/ClassLogin.tsx (2)
259-272: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Persist and navigate after successful MFA verification.
This is a login flow, but after
mfaClient.verify()succeeds it only updates local wizard state. Save the credentials and navigate like the password-login success path, otherwise the user completes MFA but remains unauthenticated in the app flow.Proposed fix
setResult({ success: true, accessToken: credentials.accessToken.substring(0, 20) + '...', }); + await auth0.credentialsManager.saveCredentials(credentials); + navigation.replace('ClassProfile', { credentials }); setMfaStep('complete');📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.if (oobCode) { credentials = await mfaClient.verify({ mfaToken, oobCode, bindingCode: verifyBindingCode || undefined, }); } else { credentials = await mfaClient.verify({ mfaToken, otp: verifyCode }); } setResult({ success: true, accessToken: credentials.accessToken.substring(0, 20) + '...', }); await auth0.credentialsManager.saveCredentials(credentials); navigation.replace('ClassProfile', { credentials }); setMfaStep('complete');🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@example/src/screens/class-based/ClassLogin.tsx` around lines 259 - 272, After mfaClient.verify succeeds in ClassLogin, the flow only updates local state and never completes authentication. Update the MFA success branch to persist the returned credentials and trigger the same post-login navigation used by the password-login success path, rather than only calling setResult and setMfaStep('complete'). Use the existing login success handling in ClassLogin as the reference so the user is fully authenticated and redirected after MFA.
418-421: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Don’t send TOTP enrollment secrets to a third-party QR service.
barcodeUricontains the TOTP secret; embedding it inhttps://api.qrserver.com/...leaks that secret off-device. Use an in-app/local QR renderer or omit the QR image and show only the deep link/secret.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@example/src/screens/class-based/ClassLogin.tsx` around lines 418 - 421, The QR image generation in ClassLogin’s Image source is leaking the TOTP secret by sending enrollmentChallenge.barcodeUri to a third-party service. Replace the api.qrserver.com URL usage with an in-app/local QR renderer, or remove the QR image entirely and present only the deep link or secret locally. Keep the fix within the ClassLogin component where the enrollment QR is rendered so the secret never leaves the device.example/src/screens/hooks/Home.tsx (1)
482-485: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Don’t send TOTP enrollment secrets to a third-party QR service.
barcodeUricontains the TOTP secret; embedding it inhttps://api.qrserver.com/...leaks that secret off-device. Use an in-app/local QR renderer or omit the QR image and show only the deep link/secret.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@example/src/screens/hooks/Home.tsx` around lines 482 - 485, The QR image generation in Home uses the third-party api.qrserver.com URL with enrollmentChallenge.barcodeUri, which leaks the TOTP secret off-device. Update the Image rendering path to avoid sending barcodeUri to an external service; instead use an in-app/local QR renderer, or remove the QR image and present only the deep link/secret in this screen. Keep the fix localized around the enrollmentChallenge.barcodeUri usage in Home.tsx.EXAMPLES-WEB.md (2)
179-205: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Remove token/secret logging from MFA examples.
Line 191/192 and Line 204 log sensitive MFA material (
secret,accessToken) to console. Docs should avoid demonstrating this pattern to prevent credential leakage in real apps.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@EXAMPLES-WEB.md` around lines 179 - 205, The MFA example in the documentation is logging sensitive credentials, so update the example flow in the mfa enrollment and verification snippets to stop printing the TOTP secret and access token to the console. Keep the surrounding MfaError handling and the enrollTotp/verifyOtp examples intact, but replace the console output in the challenge.type === 'totp' and successful verify paths with non-sensitive guidance or remove those logs entirely.
275-276: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Web direct-auth support note conflicts with the support matrix.
Line 275 says web supports
auth.passwordRealm(), but the README support table marksauth.passwordRealm()as not supported on web. Please align these docs to one authoritative behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@EXAMPLES-WEB.md` around lines 275 - 276, The web direct-auth note conflicts with the support matrix for auth.passwordRealm(), so update the documentation to state one consistent behavior across both places. Use the relevant auth method references in EXAMPLES-WEB.md, especially auth.passwordRealm(), auth.createUser(), auth.resetPassword(), and MFA Flexible Factors Grant, and either remove the web support claim or adjust the matrix so both docs match the same supported/unsupported status.EXAMPLES.md (1)
1818-1820: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Avoid logging MFA secrets/codes/tokens in sample code.
These lines print sensitive values (
secret,oobCode,accessToken) and can leak credentials in app/device logs. Please switch examples to redacted or non-sensitive status messages.Also applies to: 1842-1842, 1858-1858, 1870-1870
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@EXAMPLES.md` around lines 1818 - 1820, The sample MFA logging in EXAMPLES.md is printing sensitive values, so update the affected example blocks to avoid outputting secrets, codes, or tokens. In the challenge-handling examples (including the code paths that reference challenge.secret, oobCode, and accessToken), replace the current console.log statements with redacted or generic status messages that confirm progress without exposing credentials. Use the relevant example sections around the MFA challenge flows to locate and update all affected snippets.ios/A0MfaClient.swift (1)
77-95: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Handle
voiceenrollment separately.Line 78 routes
.voicethrough the sameenroll(...phoneNumber:)call as.phone, so a JS request withfactorType: 'voice'loses the channel selection on iOS while Android keeps it distinct. That means voice enrollment will behave like SMS here unless you call a voice-specific native path or rejectvoiceas unsupported on iOS.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ios/A0MfaClient.swift` around lines 77 - 95, The `.voice` case in `A0MfaClient.enroll` is currently sharing the same `enroll(mfaToken:phoneNumber:)` path as `.phone`, which drops the channel distinction for iOS. Update the `switch factorType` handling so `voice` is either routed through a voice-specific native enrollment path in `mfaClient` or explicitly rejected as unsupported, while keeping `.phone` on the SMS/phone-number flow. Use the existing `factorType` switch and `mfaClient.enroll` call site to locate the change.src/core/models/__tests__/ErrorCodes.spec.ts (1)
257-265: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Avoid
as anycasts in the overlap checks.The
includes(code as any)casts suppress the type mismatch between the differently-typed literal arrays. Typing the comparison arrays asstring[](or casting once) keeps the test type-safe.♻️ Suggested fix
- const mfaArray = Object.values(MfaErrorCodes); - const webAuthArray = Object.values(WebAuthErrorCodes); - const credentialsArray = Object.values(CredentialsManagerErrorCodes); - const dpopArray = Object.values(DPoPErrorCodes); + const mfaArray: string[] = Object.values(MfaErrorCodes); + const webAuthArray: string[] = Object.values(WebAuthErrorCodes); + const credentialsArray: string[] = Object.values( + CredentialsManagerErrorCodes + ); + const dpopArray: string[] = Object.values(DPoPErrorCodes); const webAuthOverlaps = mfaArray.filter((code) => - webAuthArray.includes(code as any) + webAuthArray.includes(code) ); const credentialsOverlaps = mfaArray.filter((code) => - credentialsArray.includes(code as any) + credentialsArray.includes(code) ); const dpopOverlaps = mfaArray.filter((code) => - dpopArray.includes(code as any) + dpopArray.includes(code) );As per coding guidelines: "Avoid using
anytypes; use strict TypeScript typing instead".📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.const mfaArray: string[] = Object.values(MfaErrorCodes); const webAuthArray: string[] = Object.values(WebAuthErrorCodes); const credentialsArray: string[] = Object.values( CredentialsManagerErrorCodes ); const dpopArray: string[] = Object.values(DPoPErrorCodes); const webAuthOverlaps = mfaArray.filter((code) => webAuthArray.includes(code) ); const credentialsOverlaps = mfaArray.filter((code) => credentialsArray.includes(code) ); const dpopOverlaps = mfaArray.filter((code) => dpopArray.includes(code) );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/core/models/__tests__/ErrorCodes.spec.ts` around lines 257 - 265, The overlap checks in ErrorCodes.spec use `includes(code as any)`, which hides a type mismatch with the literal arrays. Update the test data types so `webAuthArray`, `credentialsArray`, and `dpopArray` are typed compatibly (for example as `string[]` or a shared string union) and then call `includes` without `as any` in the `mfaArray.filter` checks. Keep the fix local to the overlap test block and preserve the existing `webAuthOverlaps`, `credentialsOverlaps`, and `dpopOverlaps` assertions.Source: Coding guidelines
src/core/models/MfaError.ts (1)
70-99: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
invalid_grant→INVALID_OTPcan mis-categorize expired/invalid MFA tokens.
invalid_grantis a generic OAuth error reused across MFA grant responses (e.g. expired or invalidmfa_token, not only a wrong OTP). Since this map is shared by enroll/challenge/verify, an expired-tokeninvalid_grantwill be surfaced asINVALID_OTP, hiding the dedicatedEXPIRED_MFA_TOKEN/INVALID_MFA_TOKENcategories. Consider distinguishing viaerror_description/jsonbefore defaulting toINVALID_OTP.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/core/models/MfaError.ts` around lines 70 - 99, The `ERROR_CODE_MAP` in `MfaError` is mapping the generic `invalid_grant` response directly to `MfaErrorCodes.INVALID_OTP`, which can misclassify expired or invalid MFA tokens. Update the MFA error parsing logic in `MfaError` so `invalid_grant` is not blindly normalized in the same way for all flows; inspect the accompanying `error_description` or parsed JSON/error payload first, then map token-expiry or token-invalid cases to `EXPIRED_MFA_TOKEN` or `INVALID_MFA_TOKEN`, and only fall back to `INVALID_OTP` when the response clearly indicates an OTP failure.src/factory/Auth0ClientFactory.web.ts (1)
26-26: 🎯 Functional Correctness | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Inspect getSpaClient and any reset/recreate logic in the web client. fd -t f 'WebAuth0Client.ts' src/platforms/web | xargs -I{} sh -c 'echo "== {} =="; rg -nP -C3 "getSpaClient|spaClient|resetSpaClientSingleton" {}' # Check whether the factory or provider resets the spa singleton on signature change. rg -nP -C3 "resetSpaClientSingleton|getSpaClient" srcRepository: auth0/react-native-auth0
Length of output: 5066
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== src/factory/Auth0ClientFactory.web.ts ==" sed -n '1,220p' src/factory/Auth0ClientFactory.web.ts | cat -n echo echo "== relevant WebAuth0Client constructor context ==" sed -n '80,130p' src/platforms/web/adapters/WebAuth0Client.ts | cat -nRepository: auth0/react-native-auth0
Length of output: 4202
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== src/factory/Auth0ClientFactory.web.ts ==" sed -n '1,220p' src/factory/Auth0ClientFactory.web.ts | cat -n echo echo "== relevant WebAuth0Client constructor context ==" sed -n '80,130p' src/platforms/web/adapters/WebAuth0Client.ts | cat -nRepository: auth0/react-native-auth0
Length of output: 4202
Key the web spa-js singleton by config signature
Auth0ClientFactory.web.tsnow caches by signature, butWebAuth0Client.getSpaClient()is still a process-wide singleton that always returns the firstAuth0Clientand ignores laterclientOptions. A new tenant/config will still reuse the stale spa-js client behind the freshWebAuth0Client, so web tenant switching won’t work as intended. Key or reset the singleton when the signature changes.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/factory/Auth0ClientFactory.web.ts` at line 26, The web SPA client singleton in WebAuth0Client.getSpaClient() is still shared across all configs, so a new Auth0ClientFactory.web.ts signature can still end up reusing the first Auth0Client. Update the singleton handling in WebAuth0Client and its getSpaClient() path so it is keyed by the same config signature used by getConfigSignature(options), or reset/recreate the cached spa-js client whenever the signature changes. Make sure the cache invalidation logic is tied to the existing Auth0ClientFactory.web.ts singleton flow so tenant/config switching returns the correct Auth0Client.src/hooks/Auth0Provider.tsx (1)
52-58: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Reset auth state when the tenant signature changes.
Recreating
clientonconfigSignaturechanges is correct, but the reducer state still contains the previous client’suseruntil the async initialization effect completes. For multi-tenant switching, clear the current user/error and set loading before initializing the new client to avoid briefly rendering the wrong tenant session.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/Auth0Provider.tsx` around lines 52 - 58, Reset the auth state when the tenant signature changes in Auth0Provider so the old client’s user/error do not persist while the new Auth0 instance initializes. Update the state management around the reducer and the initialization effect tied to configSignature to clear the current user and error and set loading true before starting the new client setup. Use the Auth0Provider, getConfigSignature, and the async initialization effect that follows the useMemo client creation as the places to apply the reset.src/platforms/native/adapters/__tests__/NativeMfaClient.spec.ts (1)
5-27: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Make the bridge mock partial or complete.
jest.Mocked<INativeBridge>requires every method onINativeBridge, but this object only provides the MFA-related subset plus a few existing methods. Under strict TS this will fail compilation; use a typedPick/partial mock for the methods this test exercises.Proposed fix
-const mockBridge: jest.Mocked<INativeBridge> = { +const mockBridge = { getMfaAuthenticators: jest.fn(), mfaEnroll: jest.fn(), mfaChallenge: jest.fn(), mfaVerify: jest.fn(), - initialize: jest.fn(), - hasValidInstance: jest.fn(), - getBundleIdentifier: jest.fn(), - authorize: jest.fn(), - clearSession: jest.fn(), - cancelWebAuth: jest.fn(), - saveCredentials: jest.fn(), - getCredentials: jest.fn(), - hasValidCredentials: jest.fn(), - clearCredentials: jest.fn(), - resumeWebAuth: jest.fn(), - getDPoPHeaders: jest.fn(), - clearDPoPKey: jest.fn(), - getSSOCredentials: jest.fn(), - getApiCredentials: jest.fn(), - clearApiCredentials: jest.fn(), - customTokenExchange: jest.fn(), -}; +} as jest.Mocked< + Pick< + INativeBridge, + 'getMfaAuthenticators' | 'mfaEnroll' | 'mfaChallenge' | 'mfaVerify' + > +>;- client = new NativeMfaClient(mockBridge); + client = new NativeMfaClient(mockBridge as unknown as INativeBridge);As per coding guidelines,
src/**/*.ts: "All TypeScript code must be written in strict mode".📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.const mockBridge = { getMfaAuthenticators: jest.fn(), mfaEnroll: jest.fn(), mfaChallenge: jest.fn(), mfaVerify: jest.fn(), } as jest.Mocked< Pick< INativeBridge, 'getMfaAuthenticators' | 'mfaEnroll' | 'mfaChallenge' | 'mfaVerify' > >;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/platforms/native/adapters/__tests__/NativeMfaClient.spec.ts` around lines 5 - 27, The `mockBridge` declaration in `NativeMfaClient.spec` is too strongly typed for the subset of `INativeBridge` methods it actually provides, which breaks strict TypeScript compilation. Update the test mock to use a partial/selected type instead of `jest.Mocked<INativeBridge>`, keeping only the methods exercised by the MFA tests (and any already-used helpers) while preserving proper Jest mocks. Use the `INativeBridge` interface and the `mockBridge` constant as the key references when adjusting the type.Source: Coding guidelines
src/platforms/native/adapters/NativeAuth0Client.ts (1)
141-145: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
The native re-sync is not atomic across sibling clients.
syncLockis instance-scoped, and it's released beforeoriginalMethod.apply(...)runs. Because the native module is shared process-wide, twoNativeAuth0Clientinstances can still interleaveinitialize()and the actual bridge call, so one request can execute against the other tenant's config. The directgetDPoPHeaderspath also bypasses this guard entirely, which leaves sender-constrained requests exposed to the same drift.Suggested direction
- private syncLock: Promise<void> = Promise.resolve(); + private static nativeCallLock: Promise<void> = Promise.resolve(); - private syncNativeConfig(): Promise<void> { - this.syncLock = this.syncLock - .catch(() => undefined) - .then(() => this.initialize(this.bridge, this.options)); - return this.syncLock; - } + private runWithNativeConfig<T>(op: () => Promise<T>): Promise<T> { + const run = NativeAuth0Client.nativeCallLock + .catch(() => undefined) + .then(async () => { + await this.initialize(this.bridge, this.options); + return op(); + }); + + NativeAuth0Client.nativeCallLock = run.then( + () => undefined, + () => undefined + ); + + return run; + } - await this.syncNativeConfig(); - return originalMethod.apply(bridge, args); + return this.runWithNativeConfig(() => + originalMethod.apply(bridge, args) + );Also applies to: 205-208
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/platforms/native/adapters/NativeAuth0Client.ts` around lines 141 - 145, The native config refresh in NativeAuth0Client is only protected by an instance-level syncLock, so sibling clients can still interleave initialize() and the subsequent bridge call and run against the wrong tenant config. Update the shared native access path in NativeAuth0Client so the re-sync and the original bridge invocation are serialized with a process-wide guard, and make sure the direct getDPoPHeaders flow uses the same protection instead of bypassing syncNativeConfig().
…into feat/flexible-factors-grant-support
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release.yml:
- Around line 23-25: The checkout step is still persisting the GitHub token in
git config, which can expose credentials to later release workflow steps. Update
the actions/checkout usage in the release workflow to set persist-credentials to
false alongside fetch-depth so the token is not retained during build or scanner
execution.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 5a551cdd-6301-44ab-a280-a7bad6761d20
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (1)
.github/workflows/release.yml
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release.yml:
- Around line 23-25: The checkout step is still persisting the GitHub token in
git config, which can expose credentials to later release workflow steps. Update
the actions/checkout usage in the release workflow to set persist-credentials to
false alongside fetch-depth so the token is not retained during build or scanner
execution.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 5a551cdd-6301-44ab-a280-a7bad6761d20
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (1)
.github/workflows/release.yml
🛑 Comments failed to post (1)
.github/workflows/release.yml (1)
23-25: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Disable credential persistence in checkout step.
actions/checkoutcurrently keeps the GitHub token in git config for later steps. Setpersist-credentials: falseto reduce token exposure during build/scanner execution.Suggested patch
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 + persist-credentials: false📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 persist-credentials: false🧰 Tools
🪛 zizmor (1.26.1)
[warning] 23-25: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release.yml around lines 23 - 25, The checkout step is still persisting the GitHub token in git config, which can expose credentials to later release workflow steps. Update the actions/checkout usage in the release workflow to set persist-credentials to false alongside fetch-depth so the token is not retained during build or scanner execution.Source: Linters/SAST tools
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/types/common.ts (1)
241-245: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the repo’s platform-only JSDoc notation here.
Lines 242-244 and Line 310 describe platform differences in prose (
On Android,Native (iOS/Android)), but these exported API docs are supposed to use the explicit platform markers instead (for example,**Android only**/**Web only**). As per coding guidelines, "Document platform-specific behavior in JSDoc with platform name only notation (e.g., iOS only, Android only)".Also applies to: 310-310
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/types/common.ts` around lines 241 - 245, The exported API JSDoc in the common types docs uses prose for platform differences instead of the repo’s required platform-only notation. Update the affected remarks blocks in the shared type documentation to use explicit markers like “Android only” or “Web only” (and the platform-specific note near the Native iOS/Android entry) rather than “On Android” or “Native (iOS/Android)”. Keep the existing meaning, but rewrite the JSDoc so the platform scope is stated only with the standardized platform tags.Source: Coding guidelines
src/platforms/web/adapters/WebMfaClient.ts (1)
76-123: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAvoid explicit
anyin the catch clause.
catch (inner: any)violates the project's strict-typing rule. Preferunknownand narrow before accessing.error. The same pattern recurs in the other catch blocks (enroll,challenge,verify); consider applying consistently.♻️ Suggested narrowing
- } catch (inner: any) { + } catch (inner: unknown) { // Only synthesize a context when spa-js reports it is missing; this // preserves a real context populated by spa-js's own login flow. - if (inner?.error !== 'invalid_request') throw inner; + if ((inner as { error?: string })?.error !== 'invalid_request') + throw inner;As per coding guidelines: "Avoid using
anytypes; use strict TypeScript typing instead".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/platforms/web/adapters/WebMfaClient.ts` around lines 76 - 123, The catch clauses in WebMfaClient use an explicit any, which violates strict TypeScript typing. Update the inner catch in getAuthenticators, and the similar catch blocks in enroll, challenge, and verify, to use unknown instead, then narrow the thrown value before reading .error. Keep the existing invalid_request fallback behavior intact by safely checking the narrowed value in WebMfaClient methods.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@EXAMPLES.md`:
- Around line 1843-1845: The OOB enrollment example is logging the follow-up
verification code, which should not be printed. Update the example around the
challenge.type === 'oob' handling to keep challenge.oobCode only in local state
or the next-step flow instead of sending it to console.log, so the EXAMPLES.md
guidance shows safe in-memory handling.
---
Nitpick comments:
In `@src/platforms/web/adapters/WebMfaClient.ts`:
- Around line 76-123: The catch clauses in WebMfaClient use an explicit any,
which violates strict TypeScript typing. Update the inner catch in
getAuthenticators, and the similar catch blocks in enroll, challenge, and
verify, to use unknown instead, then narrow the thrown value before reading
.error. Keep the existing invalid_request fallback behavior intact by safely
checking the narrowed value in WebMfaClient methods.
In `@src/types/common.ts`:
- Around line 241-245: The exported API JSDoc in the common types docs uses
prose for platform differences instead of the repo’s required platform-only
notation. Update the affected remarks blocks in the shared type documentation to
use explicit markers like “Android only” or “Web only” (and the
platform-specific note near the Native iOS/Android entry) rather than “On
Android” or “Native (iOS/Android)”. Keep the existing meaning, but rewrite the
JSDoc so the platform scope is stated only with the standardized platform tags.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 7775b19f-fc18-46d0-9646-035a07b873e7
📒 Files selected for processing (14)
EXAMPLES-WEB.mdEXAMPLES.mdandroid/src/main/java/com/auth0/react/MfaClient.ktexample/src/App.web.tsxexample/src/screens/class-based/ClassApiTests.tsxexample/src/screens/class-based/ClassLogin.tsxexample/src/screens/hooks/Home.tsxios/A0MfaClient.swiftsrc/core/models/MfaError.tssrc/core/models/__tests__/MfaError.spec.tssrc/platforms/web/adapters/WebMfaClient.tssrc/platforms/web/adapters/__tests__/WebMfaClient.spec.tssrc/types/common.tssrc/types/parameters.ts
✅ Files skipped from review due to trivial changes (2)
- src/platforms/web/adapters/tests/WebMfaClient.spec.ts
- EXAMPLES-WEB.md
🚧 Files skipped from review as they are similar to previous changes (9)
- src/core/models/tests/MfaError.spec.ts
- src/core/models/MfaError.ts
- src/types/parameters.ts
- example/src/screens/class-based/ClassApiTests.tsx
- ios/A0MfaClient.swift
- example/src/screens/class-based/ClassLogin.tsx
- example/src/screens/hooks/Home.tsx
- android/src/main/java/com/auth0/react/MfaClient.kt
- example/src/App.web.tsx
…into feat/flexible-factors-grant-support
Adds first-class MFA support to the SDK across iOS, Android, and Web, exposing the Flexible Factors flow through a single consistent API:
mfa.getAuthenticators()— list a user's enrolled factorsmfa.enroll()— enroll a new factor (OTP, SMS, voice, email, push)mfa.challenge()— trigger a challenge for an existing factormfa.verify()— verify a code and exchange the MFA token for credentialsAn
MfaFactorTypeenum and a dedicatedMfaError(withMfaErrorCodes) are exported publicly for type-safe usage and error handling.Usage