Skip to content
Merged
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ Next, define the Manifest Placeholders for the Auth0 Domain and Scheme which are
apply plugin: 'com.android.application'

android {
compileSdkVersion 35
compileSdkVersion 36
defaultConfig {
applicationId "com.auth0.samples"
minSdkVersion 24
targetSdkVersion 35
targetSdkVersion 36
//...

//---> Add the next line
Expand Down
36 changes: 32 additions & 4 deletions V4_MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,21 @@ android {

v4 requires:

- **Gradle**: 8.10.2 or later
- **Android Gradle Plugin (AGP)**: 8.8.2 or later
- **Gradle**: 8.11.1 or later
- **Android Gradle Plugin (AGP)**: 8.10.1 or later

Update your `gradle/wrapper/gradle-wrapper.properties`:

```properties
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
```

Update your root `build.gradle`:

```groovy
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:8.8.2'
classpath 'com.android.tools.build:gradle:8.10.1'
}
}
```
Expand All @@ -67,6 +67,34 @@ buildscript {
- [signinWithPasskey()](auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.kt#L235-L253) - Sign in a user using passkeys
- [signupWithPasskey()](auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.kt#L319-L344) - Sign up a user and returns a challenge for key generation

## Dependency Changes

### ⚠️ Gson 2.8.9 → 2.11.0 (Transitive Dependency)

v4 updates the internal Gson dependency from **2.8.9** to **2.11.0**. While the SDK does not expose Gson types in its public API, Gson is included as a transitive runtime dependency. If your app also uses Gson, be aware of the following changes introduced in Gson 2.10+:

- **`TypeToken` with unresolved type variables is rejected at runtime.** Code like `object : TypeToken<List<T>>() {}` (where `T` is a generic parameter) will throw `IllegalArgumentException`. Use Kotlin `reified` type parameters or pass concrete types instead.
- **Strict type coercion is enforced.** Gson no longer silently coerces JSON objects or arrays to `String`. If your code relies on this behavior, you will see `JsonSyntaxException`.
- **Built-in ProGuard/R8 rules are included.** Gson 2.11.0 ships its own keep rules, so you may be able to remove custom Gson ProGuard rules from your project.

If you need to pin Gson to an older version, you can use Gradle's `resolutionStrategy`:
Copy link
Contributor

@pmathew92 pmathew92 Feb 10, 2026

Choose a reason for hiding this comment

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

You can also add suggestion to ignore the Gson from the SDK. Add code snippet for the same

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


```groovy
configurations.all {
resolutionStrategy.force 'com.google.code.gson:gson:2.8.9'
}
```

Alternatively, you can exclude Gson from the SDK entirely and provide your own version:

```groovy
implementation('com.auth0.android:auth0:<version>') {
exclude group: 'com.google.code.gson', module: 'gson'
}
implementation 'com.google.code.gson:gson:2.8.9' // your preferred version
```

> **Note:** Pinning or excluding is not recommended long-term, as the SDK has been tested and validated against Gson 2.11.0.

## Getting Help

Expand Down
24 changes: 12 additions & 12 deletions auth0/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ logger.lifecycle("Using version ${version} for ${name}")

android {
namespace 'com.auth0.android.auth0'
compileSdk 35
compileSdk 36

buildFeatures {
buildConfig = true
}

defaultConfig {
minSdkVersion 21
targetSdk 35
targetSdk 36
versionCode 1
versionName project.version

Expand Down Expand Up @@ -81,34 +81,34 @@ android {

ext {
okhttpVersion = '4.12.0'
Copy link
Contributor

Choose a reason for hiding this comment

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

Okhttp can also be increased to version 5

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OkHttp 5.0.0 is now stable (released July 2025, latest 5.3.2), but it has massive breaking changes: separate JVM/Android artifacts, MockWebServer moved to mockwebserver3 package with new coordinates, RecordedRequest.path renamed to .target, .body is now ByteString, MockResponse is immutable with a Builder, requires Okio 3.x, etc. This would touch virtually every test file.
Will creqate a seperate Ticket and resolve with testcases which are ignored currently.

Copy link
Contributor

Choose a reason for hiding this comment

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

Create a ticket to track this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

SDK-7768

coroutinesVersion = '1.7.3'
coroutinesVersion = '1.10.2'
biometricLibraryVersion = '1.1.0'
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a new version available for biometricLibraryVersion ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Biometric version(1.1.0) latest stable release (Jan 2021)
beyond it is alpha (1.4.0-alpha05 as of Dec 2025)

}


dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'androidx.browser:browser:1.4.0'
implementation 'androidx.core:core-ktx:1.15.0'
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'androidx.browser:browser:1.9.0'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"

implementation "com.squareup.okhttp3:logging-interceptor:$okhttpVersion"
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'com.google.androidbrowserhelper:androidbrowserhelper:2.4.0'
implementation 'com.google.code.gson:gson:2.11.0'
implementation 'com.google.androidbrowserhelper:androidbrowserhelper:2.5.0'

implementation "androidx.biometric:biometric:$biometricLibraryVersion"

testImplementation 'junit:junit:4.13.2'
testImplementation 'org.hamcrest:java-hamcrest:2.0.0.0'
testImplementation 'org.mockito:mockito-core:5.7.0'
testImplementation 'org.mockito.kotlin:mockito-kotlin:5.1.0'
testImplementation 'org.mockito:mockito-core:5.14.0'
testImplementation 'org.mockito.kotlin:mockito-kotlin:5.4.0'
testImplementation "com.squareup.okhttp3:mockwebserver:$okhttpVersion"
testImplementation "com.squareup.okhttp3:okhttp-tls:$okhttpVersion"
testImplementation 'com.jayway.awaitility:awaitility:1.7.0'
Copy link
Contributor

Choose a reason for hiding this comment

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

Check where is this used com.jayway.awaitility:awaitility ? If not required , remove them ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Awaitility removal ❌ Cannot remove
Awaitility is actively used in 5 test matcher utility files:

CallbackMatcher.java
AuthCallbackMatcher.java
AuthenticationCallbackMatcher.java
MyAccountCallbackMatcher.kt
ManagementCallbackMatcher.java
All import com.jayway.awaitility.Awaitility.await and ConditionTimeoutException.

testImplementation 'org.robolectric:robolectric:4.14.1'
testImplementation 'androidx.test.espresso:espresso-intents:3.5.1'
testImplementation 'org.robolectric:robolectric:4.15.1'
testImplementation 'androidx.test.espresso:espresso-intents:3.6.1'
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion"

testImplementation "androidx.biometric:biometric:$biometricLibraryVersion"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ public class AuthenticationAPIClientTest {
defaultLocale
)
)
val body = bodyFromRequest<String>(request)
val body = bodyFromRequest<Any>(request)
assertThat(request.path, Matchers.equalTo("/oauth/token"))
assertThat(body, Matchers.hasEntry("client_id", CLIENT_ID))
assertThat(
Expand Down Expand Up @@ -254,7 +254,7 @@ public class AuthenticationAPIClientTest {
defaultLocale
)
)
val body = bodyFromRequest<String>(request)
val body = bodyFromRequest<Any>(request)
assertThat(request.path, Matchers.equalTo("/passkey/register"))
assertThat(body, Matchers.hasEntry("client_id", CLIENT_ID))
assertThat(body, Matchers.hasEntry("realm", MY_CONNECTION))
Expand Down Expand Up @@ -1034,7 +1034,7 @@ public class AuthenticationAPIClientTest {
)
)
assertThat(request.path, Matchers.equalTo("/dbconnections/signup"))
val body = bodyFromRequest<String>(request)
val body = bodyFromRequest<Any>(request)
assertThat(body, Matchers.hasEntry("email", SUPPORT_AUTH0_COM))
assertThat(body, Matchers.hasEntry("username", SUPPORT))
assertThat(body, Matchers.hasEntry("password", PASSWORD))
Expand All @@ -1058,7 +1058,7 @@ public class AuthenticationAPIClientTest {
)
)
assertThat(request.path, Matchers.equalTo("/dbconnections/signup"))
val body = bodyFromRequest<String>(request)
val body = bodyFromRequest<Any>(request)
assertThat(body, Matchers.hasEntry("email", SUPPORT_AUTH0_COM))
assertThat(body, Matchers.hasEntry("username", SUPPORT))
assertThat(body, Matchers.hasEntry("password", PASSWORD))
Expand Down Expand Up @@ -1361,7 +1361,7 @@ public class AuthenticationAPIClientTest {
)
)
assertThat(request.path, Matchers.equalTo("/dbconnections/signup"))
val body = bodyFromRequest<String>(request)
val body = bodyFromRequest<Any>(request)
assertThat(body, Matchers.hasEntry("email", SUPPORT_AUTH0_COM))
assertThat(body, Matchers.hasEntry("username", SUPPORT))
assertThat(body, Matchers.hasEntry("password", PASSWORD))
Expand Down Expand Up @@ -3132,8 +3132,8 @@ public class AuthenticationAPIClientTest {
assertThat(exception.cause, Matchers.instanceOf(DPoPException::class.java))
}

private fun <T> bodyFromRequest(request: RecordedRequest): Map<String, T> {
val mapType = object : TypeToken<Map<String?, T>?>() {}.type
private inline fun <reified T> bodyFromRequest(request: RecordedRequest): Map<String, T> {
val mapType = object : TypeToken<Map<String, T>>() {}.type
return gson.fromJson(request.body.readUtf8(), mapType)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,8 +441,8 @@ public class UsersAPIClientTest {
)
}

private fun <T> bodyFromRequest(request: RecordedRequest): Map<String, T> {
val mapType = object : TypeToken<Map<String?, T>?>() {}.type
private inline fun <reified T> bodyFromRequest(request: RecordedRequest): Map<String, T> {
val mapType = object : TypeToken<Map<String, T>>() {}.type
return gson.fromJson(request.body.readUtf8(), mapType)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,8 @@ public class MyAccountAPIClientTest {
assertThat(body, Matchers.hasEntry("type", "push-notification" as Any))
}

private fun <T> bodyFromRequest(request: RecordedRequest): Map<String, T> {
val mapType = object : TypeToken<Map<String?, T>?>() {}.type
private inline fun <reified T> bodyFromRequest(request: RecordedRequest): Map<String, T> {
val mapType = object : TypeToken<Map<String, T>>() {}.type
return gson.fromJson(request.body.readUtf8(), mapType)
}

Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.8.2'
classpath 'com.android.tools.build:gradle:8.10.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jacoco:org.jacoco.core:0.8.5"
classpath "org.jacoco:org.jacoco.core:0.8.12"
}
}

Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
4 changes: 2 additions & 2 deletions sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ plugins {

android {
namespace 'com.auth0.sample'
compileSdk 35
compileSdk 36

defaultConfig {
minSdk 24
targetSdk 35
targetSdk 36
versionCode 1
versionName "1.0"

Expand Down
Loading