Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -560,15 +560,15 @@ authentication
requirements?.enroll?.let { enrollTypes ->
println("User needs to enroll MFA")
println("Available enrollment types: ${enrollTypes.map { it.type }}")
// Example output: ["otp", "sms", "push-notification"]
// Example output: ["otp", "phone", "push-notification"]
// Proceed with MFA enrollment using one of these types
}

// Check if challenge is available (user already enrolled)
requirements?.challenge?.let { challengeTypes ->
println("User has enrolled MFA factors")
println("Available challenge types: ${challengeTypes.map { it.type }}")
// Example output: ["otp", "sms"]
// Example output: ["otp", "phone"]
// Get authenticators and challenge one of them
}

Expand Down Expand Up @@ -650,14 +650,14 @@ try {
requirements?.enroll?.let { enrollTypes ->
println("User needs to enroll MFA")
println("Available enrollment types: ${enrollTypes.map { it.type }}")
// Example output: ["otp", "sms", "push-notification"]
// Example output: ["otp", "phone", "push-notification"]
}

// Check if challenge is available
requirements?.challenge?.let { challengeTypes ->
println("User has enrolled MFA factors")
println("Available challenge types: ${challengeTypes.map { it.type }}")
// Example output: ["otp", "sms"]
// Example output: ["otp", "phone"]
}

// Proceed with MFA flow using mfaToken
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,19 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
* ## Usage
*
* ```kotlin
* mfaClient.getAuthenticators(listOf("otp", "oob"))
* mfaClient.getAuthenticators(listOf("otp", "phone"))
Comment thread
NandanPrabhu marked this conversation as resolved.
* .start(object : Callback<List<Authenticator>, MfaListAuthenticatorsException> {
* override fun onSuccess(result: List<Authenticator>) {
* // Only OTP and OOB authenticators returned
* // Only authenticators whose `type` is "otp" or "phone" are returned
* }
* override fun onFailure(error: MfaListAuthenticatorsException) { }
* })
* ```
*
* @param factorsAllowed Array of factor types to filter the authenticators (e.g., `["otp", "oob", "recovery-code"]`).
* Filtering matches each authenticator's [Authenticator.type] field against the
* provided values using exact (case-sensitive) equality.
*
* @param factorsAllowed Array of factor types to filter the authenticators (e.g., `["otp", "phone", "email", "recovery-code"]`).
* Must contain at least one factor type.
Comment on lines +127 to 140

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What is the actual type field value returned by Auth0's GET /mfa/authenticators endpoint for a phone/SMS-based authenticator — "phone" or "oob"?

💡 Result:

For phone or SMS-based authenticators in Auth0, the actual field returned by the GET /mfa/authenticators endpoint is authenticator_type, and its value is "oob" [1][2]. While you may encounter the term "phone" in other parts of the Auth0 ecosystem—such as in configuration parameters, Management API requests, or MFA challenge requirement lists [3][4][5][2]—the specific authenticator_type field used to identify SMS or Voice factors within the list of enrolled authenticators is "oob" [1][2]. The specific transport method (e.g., SMS or Voice) is then provided in a separate field called oob_channel [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the relevant client and test references.
git ls-files 'auth0/src/main/java/com/auth0/android/authentication/mfa/MfaApiClient.kt' \
             'auth0/src/test/**/MfaApiClientTest.kt' \
             'auth0/src/**/MfaApiClientTest.kt' \
             'auth0/src/**/mfa/**' | sed 's#^`#-` #'

printf '\n== MfaApiClient.kt excerpt ==\n'
sed -n '110,155p' auth0/src/main/java/com/auth0/android/authentication/mfa/MfaApiClient.kt

printf '\n== Search for factor/type values in tests ==\n'
rg -n '"type"\s*:\s*"(oob|otp|phone|email|recovery-code)"|factorsAllowed|Authenticator.type|oob_channel|authenticator_type' auth0/src/test auth0/src/main -g '*MfaApiClientTest.kt' -g '*.kt'

Repository: auth0/Auth0.Android

Length of output: 8536


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the specific test regions mentioned by the review comment.
test_file=$(git ls-files 'auth0/src/test/**/MfaApiClientTest.kt' 'auth0/src/**/MfaApiClientTest.kt' | head -n 1)
if [ -z "$test_file" ]; then
  echo "MfaApiClientTest.kt not found"
  exit 0
fi

printf 'Using test file: %s\n' "$test_file"

for range in '240,270' '296,330' '340,390' '830,860'; do
  printf '\n== %s lines %s ==\n' "$test_file" "$range"
  sed -n "${range}p" "$test_file"
done

Repository: auth0/Auth0.Android

Length of output: 6455


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the surrounding code and nearby tests that define the expected factor values.
printf '\n== MfaApiClient.kt around the documented example ==\n'
sed -n '120,145p' auth0/src/main/java/com/auth0/android/authentication/mfa/MfaApiClient.kt

printf '\n== Search for API/model docs and test fixtures mentioning MFA authenticator types ==\n'
rg -n 'oob|otp|phone|email|recovery-code|authenticator_type|Authenticator.type|getAuthenticators' auth0/src/main/java auth0/src/test -g '*.kt'

Repository: auth0/Auth0.Android

Length of output: 50377


Use oob here instead of phone/email
GET /mfa/authenticators returns Authenticator.type == "oob" for SMS/email authenticators, so the example currently suggests filter values that won’t match those items. Update the KDoc sample and factorsAllowed examples to use oob.

🤖 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 `@auth0/src/main/java/com/auth0/android/authentication/mfa/MfaApiClient.kt`
around lines 127 - 140, The KDoc example in MfaApiClient.getAuthenticators uses
outdated factor values that won’t match SMS/email authenticators. Update the
sample callback and the `@param` factorsAllowed examples to use "oob" instead of
"phone" and "email", keeping the exact-match filtering note aligned with
Authenticator.type.

* @return a request to configure and start that will yield a list of [Authenticator]
*
Expand Down Expand Up @@ -307,11 +310,11 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
* transparently by the SDK.
*
* **Filtering:**
* Authenticators are filtered by their effective type:
* - OOB authenticators: matched by their channel ("sms" or "email")
* - Other authenticators: matched by their type ("otp", "recovery-code", etc.)
* An authenticator is included when [Authenticator.type] exactly matches one of the
* provided [factorsAllowed] values (case-sensitive equality). This mirrors the
* filtering behavior of the Auth0.swift SDK.
*
* @param factorsAllowed List of factor types to include (e.g., ["sms", "email", "otp"])
* @param factorsAllowed List of factor types to include (e.g., ["phone", "email", "otp"])
* @return A JsonAdapter that produces a filtered list of authenticators
*/
private fun createFilteringAuthenticatorsAdapter(factorsAllowed: List<String>): JsonAdapter<List<Authenticator>> {
Expand All @@ -321,66 +324,12 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
val allAuthenticators = baseAdapter.fromJson(reader, metadata)

return allAuthenticators.filter { authenticator ->
matchesFactorType(authenticator, factorsAllowed)
factorsAllowed.contains(authenticator.type)
}
}
}
}

/**
* Checks if an authenticator matches any of the allowed factor types.
*
* The matching logic handles various factor type aliases:
* - "sms" or "phone": matches OOB authenticators with SMS channel
* - "email": matches OOB authenticators with email channel
* - "otp" or "totp": matches time-based one-time password authenticators
* - "oob": matches any out-of-band authenticator regardless of channel
* - "recovery-code": matches recovery code authenticators
* - "push-notification": matches push notification authenticators
*
* @param authenticator The authenticator to check
* @param factorsAllowed List of allowed factor types
* @return true if the authenticator matches any allowed factor type
*/
private fun matchesFactorType(
authenticator: Authenticator,
factorsAllowed: List<String>
): Boolean {
val effectiveType = getEffectiveType(authenticator)

return factorsAllowed.any { factor ->
val normalizedFactor = factor.lowercase(java.util.Locale.ROOT)
when (normalizedFactor) {
"sms", "phone" -> effectiveType == "sms" || effectiveType == "phone"
"email" -> effectiveType == "email"
"otp", "totp" -> effectiveType == "otp" || effectiveType == "totp"
"oob" -> authenticator.authenticatorType == "oob" || authenticator.type == "oob"
"recovery-code" -> effectiveType == "recovery-code"
"push-notification" -> effectiveType == "push-notification"
else -> effectiveType == normalizedFactor ||
authenticator.authenticatorType?.lowercase(java.util.Locale.ROOT) == normalizedFactor ||
authenticator.type.lowercase(java.util.Locale.ROOT) == normalizedFactor
}
}
}

/**
* Resolves the effective type of an authenticator for filtering purposes.
*
* OOB (out-of-band) authenticators use their channel ("sms" or "email") as the
* effective type, since users typically filter by delivery method rather than
* the generic "oob" type. Other authenticators use their authenticatorType directly.
*
* @param authenticator The authenticator to get the type for
* @return The effective type string used for filtering
*/
private fun getEffectiveType(authenticator: Authenticator): String {
return when (authenticator.authenticatorType) {
"oob" -> authenticator.oobChannel ?: "oob"
else -> authenticator.authenticatorType ?: authenticator.type
}
}

/**
* Helper function for OOB enrollment (SMS, email, push).
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ public class MfaApiClientTest {

@Test
public fun shouldGetAuthenticatorsWithCallback(): Unit {
val json = """[{"id": "sms|dev_123", "authenticator_type": "oob", "active": true}]"""
val json = """[{"id": "sms|dev_123", "type": "oob", "authenticator_type": "oob", "active": true}]"""
enqueueMockResponse(json)

val callback = MockCallback<List<Authenticator>, MfaListAuthenticatorsException>()
Expand Down
Loading