Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ec4c634
doc: Removed EA tag from N2W APIs (#920)
pmathew92 Feb 26, 2026
f0ca8f6
chore: Removed claude PR-analyzer workflow (#921)
pmathew92 Feb 26, 2026
43f9358
SDK-7858 fix: Handle ProviderException in PKCS1→OAEP key migration to…
utkrishtsahu Feb 26, 2026
692d4be
fix : Added the missing user agent to MyAccount and MFAApiClient (#926)
pmathew92 Mar 2, 2026
73d6dc1
fix: correct rl-wrapper flag from --suppress_output to --suppress-output
sanchitmehtagit Mar 2, 2026
ad1c112
Merge branch 'main' into fix/rl-wrapper-flag
sanchitmehtagit Mar 2, 2026
38ae551
fix: correct rl-wrapper flag from --suppress_output to --suppress-out…
sanchitmehtagit Mar 2, 2026
146448c
refactor : Deprecated the UsersAPIClient (#930)
pmathew92 Mar 4, 2026
15eb856
fix: Wrap ProviderException as CryptoException to enable key recovery…
utkrishtsahu Mar 6, 2026
493a9ba
fix: Wrap ProviderException as CryptoException to enable key recovery…
utkrishtsahu Mar 6, 2026
719cb1c
fix: Revert sample app changes
utkrishtsahu Mar 6, 2026
4671ebb
doc: remove EA note for DPoP (#933)
pmathew92 Mar 6, 2026
9506d95
refactor : Deprecate the existing MFA APIs in `AuthenticationAPIClien…
pmathew92 Mar 9, 2026
307cebe
Merge branch 'main' into SDK-7858-fix-Handle-ProviderException-in-PKC…
pmathew92 Mar 10, 2026
f249712
adding UT cases as per review comments
utkrishtsahu Mar 10, 2026
f6c4126
fix: Handle ProviderException in PKCS1→OAEP key migration to prevent …
utkrishtsahu Mar 11, 2026
10478a7
Release 3.14.0 (#935)
pmathew92 Mar 11, 2026
8b42d6d
Added missing CryptoUtil test cases
pmathew92 Mar 12, 2026
753fd81
Fixed merge conflict
pmathew92 Mar 12, 2026
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
2 changes: 1 addition & 1 deletion .github/actions/rl-scanner/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ runs:
--repository "${{ github.repository }}" \
--commit "${{ github.sha }}" \
--build-env "github_actions" \
--suppress_output
--suppress-output

# Check the outcome of the scanner
if [ $? -ne 0 ]; then
Expand Down
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.13.0
3.14.0
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Change Log

## [3.14.0](https://github.com/auth0/Auth0.Android/tree/3.14.0) (2026-03-11)
[Full Changelog](https://github.com/auth0/Auth0.Android/compare/3.13.0...3.14.0)

**Deprecated**
- refactor : Deprecate the existing MFA APIs in `AuthenticationAPIClient` [\#932](https://github.com/auth0/Auth0.Android/pull/932) ([pmathew92](https://github.com/pmathew92))
- refactor : Deprecated the UsersAPIClient [\#930](https://github.com/auth0/Auth0.Android/pull/930) ([pmathew92](https://github.com/pmathew92))

**Fixed**
- fix: Handle ProviderException in PKCS1→OAEP key migration to prevent saveCredentials() crash [\#924](https://github.com/auth0/Auth0.Android/pull/924) ([utkrishtsahu](https://github.com/utkrishtsahu))
- fix : Added the missing user agent to MyAccount and MFAApiClient [\#926](https://github.com/auth0/Auth0.Android/pull/926) ([pmathew92](https://github.com/pmathew92))

## [3.13.0](https://github.com/auth0/Auth0.Android/tree/3.13.0) (2026-02-06)
[Full Changelog](https://github.com/auth0/Auth0.Android/compare/3.12.2...3.13.0)

Expand Down
14 changes: 4 additions & 10 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
- [Specify a Custom Logout URL](#specify-a-custom-logout-url)
- [Trusted Web Activity](#trusted-web-activity)
- [Ephemeral Browsing [Experimental]](#ephemeral-browsing-experimental)
- [DPoP [EA]](#dpop-ea)
- [DPoP](#dpop)
- [Authentication API](#authentication-api)
- [Login with database connection](#login-with-database-connection)
- [Login using MFA with One Time Password code](#login-using-mfa-with-one-time-password-code)
Expand All @@ -31,7 +31,7 @@
- [Get user information](#get-user-information)
- [Custom Token Exchange](#custom-token-exchange)
- [Native to Web SSO login](#native-to-web-sso-login)
- [DPoP [EA]](#dpop-ea-1)
- [DPoP](#dpop-1)
- [My Account API](#my-account-api)
- [Enroll a new passkey](#enroll-a-new-passkey)
- [Get Available Factors](#get-available-factors)
Expand Down Expand Up @@ -265,10 +265,7 @@ WebAuthProvider.login(account)
```
</details>

## DPoP [EA]

> [!NOTE]
> This feature is currently available in [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access). Please reach out to Auth0 support to get it enabled for your tenant.
## DPoP

[DPoP](https://www.rfc-editor.org/rfc/rfc9449.html) (Demonstrating Proof of Possession) is an application-level mechanism for sender-constraining OAuth 2.0 access and refresh tokens by proving that the app is in possession of a certain private key. You can enable it by calling the `useDPoP(context)` method on the login Builder.

Expand Down Expand Up @@ -1643,10 +1640,7 @@ authentication
```
</details>

## DPoP [EA]

> [!NOTE]
> This feature is currently available in [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access). Please reach out to Auth0 support to get it enabled for your tenant.
## DPoP

[DPoP](https://www.rfc-editor.org/rfc/rfc9449.html) (Demonstrating Proof of Possession) is an application-level mechanism for sender-constraining OAuth 2.0 access and refresh tokens by proving that the app is in possession of a certain private key. You can enable it by calling the `useDPoP(context: Context)` method. This ensures that DPoP proofs are generated for requests made through the AuthenticationAPI client.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
return loginWithToken(requestParameters)
}


/**
* Log in a user using the One Time Password code after they have received the 'mfa_required' error.
* The MFA token tells the server the username or email, password, and realm values sent on the first request.
Expand All @@ -196,6 +197,10 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
* MFA application such as Google Authenticator or Guardian.
* @return a request to configure and start that will yield [Credentials]
*/
@Deprecated(
message = "loginWithOTP is deprecated and will be removed in the next major version of the SDK. Use the APIs in the [com.auth0.android.authentication.mfa.MfaApiClient] class instead.",
level = DeprecationLevel.WARNING
)
public fun loginWithOTP(mfaToken: String, otp: String): AuthenticationRequest {
val parameters = ParameterBuilder.newBuilder()
.setGrantType(ParameterBuilder.GRANT_TYPE_MFA_OTP)
Expand Down Expand Up @@ -409,6 +414,10 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
* This is usually an OTP-like code delivered as part of the challenge message.
* @return a request to configure and start that will yield [Credentials]
*/
@Deprecated(
message = "loginWithOOB is deprecated and will be removed in the next major version of the SDK. Use the APIs in the [com.auth0.android.authentication.mfa.MfaApiClient] class instead.",
level = DeprecationLevel.WARNING
)
public fun loginWithOOB(
mfaToken: String,
oobCode: String,
Expand Down Expand Up @@ -445,6 +454,10 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
* @return a request to configure and start that will yield [Credentials]. It might also include a [recoveryCode] field,
* which your application must display to the end-user to be stored securely for future use.
*/
@Deprecated(
message = "loginWithRecoveryCode is deprecated and will be removed in the next major version of the SDK. Use the APIs in the [com.auth0.android.authentication.mfa.MfaApiClient] class instead.",
level = DeprecationLevel.WARNING
)
public fun loginWithRecoveryCode(
mfaToken: String,
recoveryCode: String
Expand Down Expand Up @@ -478,6 +491,10 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
* @param authenticatorId The ID of the authenticator to challenge.
* @return a request to configure and start that will yield [Challenge]
*/
@Deprecated(
message = "multifactorChallenge is deprecated and will be removed in the next major version of the SDK. Use the APIs in the [com.auth0.android.authentication.mfa.MfaApiClient] class instead.",
level = DeprecationLevel.WARNING
)
public fun multifactorChallenge(
mfaToken: String,
challengeType: String? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import androidx.annotation.VisibleForTesting
import com.auth0.android.Auth0
import com.auth0.android.Auth0Exception
import com.auth0.android.authentication.ParameterBuilder
import com.auth0.android.authentication.mfa.MfaException.*
import com.auth0.android.authentication.mfa.MfaException.MfaChallengeException
import com.auth0.android.authentication.mfa.MfaException.MfaEnrollmentException
import com.auth0.android.authentication.mfa.MfaException.MfaListAuthenticatorsException
import com.auth0.android.authentication.mfa.MfaException.MfaVerifyException
import com.auth0.android.request.ErrorAdapter
import com.auth0.android.request.JsonAdapter
import com.auth0.android.request.Request
Expand Down Expand Up @@ -58,19 +61,27 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA

// Specialized factories for MFA-specific errors
private val listAuthenticatorsFactory: RequestFactory<MfaListAuthenticatorsException> by lazy {
RequestFactory(auth0.networkingClient, createListAuthenticatorsErrorAdapter())
RequestFactory(auth0.networkingClient, createListAuthenticatorsErrorAdapter()).apply {
setAuth0ClientInfo(auth0.auth0UserAgent.value)
}
}

private val enrollmentFactory: RequestFactory<MfaEnrollmentException> by lazy {
RequestFactory(auth0.networkingClient, createEnrollmentErrorAdapter())
RequestFactory(auth0.networkingClient, createEnrollmentErrorAdapter()).apply {
setAuth0ClientInfo(auth0.auth0UserAgent.value)
}
}

private val challengeFactory: RequestFactory<MfaChallengeException> by lazy {
RequestFactory(auth0.networkingClient, createChallengeErrorAdapter())
RequestFactory(auth0.networkingClient, createChallengeErrorAdapter()).apply {
setAuth0ClientInfo(auth0.auth0UserAgent.value)
}
}

private val verifyFactory: RequestFactory<MfaVerifyException> by lazy {
RequestFactory(auth0.networkingClient, createVerifyErrorAdapter())
RequestFactory(auth0.networkingClient, createVerifyErrorAdapter()).apply {
setAuth0ClientInfo(auth0.auth0UserAgent.value)
}
}

/**
Expand Down Expand Up @@ -175,7 +186,11 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
*/
public fun enroll(type: MfaEnrollmentType): Request<EnrollmentChallenge, MfaEnrollmentException> {
return when (type) {
is MfaEnrollmentType.Phone -> enrollOob(oobChannel = "sms", phoneNumber = type.phoneNumber)
is MfaEnrollmentType.Phone -> enrollOob(
oobChannel = "sms",
phoneNumber = type.phoneNumber
)

is MfaEnrollmentType.Email -> enrollOob(oobChannel = "email", email = type.email)
is MfaEnrollmentType.Otp -> enrollOtpInternal()
is MfaEnrollmentType.Push -> enrollOob(oobChannel = "auth0")
Expand Down Expand Up @@ -228,7 +243,6 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
}



/**
* Verifies an MFA challenge using the specified verification type.
*
Expand Down Expand Up @@ -290,7 +304,7 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
return object : JsonAdapter<List<Authenticator>> {
override fun fromJson(reader: Reader, metadata: Map<String, Any>): List<Authenticator> {
val allAuthenticators = baseAdapter.fromJson(reader, metadata)

return allAuthenticators.filter { authenticator ->
matchesFactorType(authenticator, factorsAllowed)
}
Expand All @@ -313,9 +327,12 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
* @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 {
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) {
Expand All @@ -325,7 +342,7 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
"oob" -> authenticator.authenticatorType == "oob" || authenticator.type == "oob"
"recovery-code" -> effectiveType == "recovery-code"
"push-notification" -> effectiveType == "push-notification"
else -> effectiveType == normalizedFactor ||
else -> effectiveType == normalizedFactor ||
authenticator.authenticatorType?.lowercase(java.util.Locale.ROOT) == normalizedFactor ||
authenticator.type.lowercase(java.util.Locale.ROOT) == normalizedFactor
}
Expand Down Expand Up @@ -370,7 +387,7 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
.addHeader(HEADER_AUTHORIZATION, "Bearer $mfaToken")
.addParameter(AUTHENTICATOR_TYPES_KEY, listOf("oob"))
.addParameter(OOB_CHANNELS_KEY, listOf(oobChannel))

if (phoneNumber != null) {
request.addParameter(PHONE_NUMBER_KEY, phoneNumber)
}
Expand Down Expand Up @@ -411,7 +428,7 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
.setGrantType(GRANT_TYPE_MFA_OOB)
.set(MFA_TOKEN_KEY, mfaToken)
.set(OUT_OF_BAND_CODE_KEY, oobCode)

if (bindingCode != null) {
parametersBuilder.set(BINDING_CODE_KEY, bindingCode)
}
Expand Down Expand Up @@ -465,7 +482,6 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
}



/**
* Creates error adapter for getAuthenticators() operations.
*/
Expand Down Expand Up @@ -643,6 +659,7 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA
private const val RECOVERY_CODE_KEY = "recovery_code"
private const val GRANT_TYPE_MFA_OTP = "http://auth0.com/oauth/grant-type/mfa-otp"
private const val GRANT_TYPE_MFA_OOB = "http://auth0.com/oauth/grant-type/mfa-oob"
private const val GRANT_TYPE_MFA_RECOVERY_CODE = "http://auth0.com/oauth/grant-type/mfa-recovery-code"
private const val GRANT_TYPE_MFA_RECOVERY_CODE =
"http://auth0.com/oauth/grant-type/mfa-recovery-code"
}
}
Loading
Loading