diff --git a/EXAMPLES.md b/EXAMPLES.md
index cae42b8ca..064bc8355 100644
--- a/EXAMPLES.md
+++ b/EXAMPLES.md
@@ -3201,10 +3201,12 @@ The Auth0 class can be configured with a `NetworkingClient`, which will be used
### Timeout configuration
```kotlin
-val netClient = DefaultClient(
- connectTimeout = 30,
- readTimeout = 30
-)
+val netClient = DefaultClient.Builder()
+ .connectTimeout(30)
+ .readTimeout(30)
+ .writeTimeout(30)
+ .callTimeout(120)
+ .build()
val account = Auth0.getInstance("{YOUR_CLIENT_ID}", "{YOUR_DOMAIN}")
account.networkingClient = netClient
@@ -3214,43 +3216,78 @@ account.networkingClient = netClient
Using Java
```java
-DefaultClient netClient = new DefaultClient(30, 30);
+DefaultClient netClient = new DefaultClient.Builder()
+ .connectTimeout(30)
+ .readTimeout(30)
+ .writeTimeout(30)
+ .callTimeout(120)
+ .build();
Auth0 account = Auth0.getInstance("client id", "domain");
account.setNetworkingClient(netClient);
```
-### Logging configuration
+
+ Legacy constructor (still supported)
```kotlin
val netClient = DefaultClient(
- enableLogging = true
+ connectTimeout = 30,
+ readTimeout = 30
)
+```
+
+
+### Logging configuration
+
+```kotlin
+val netClient = DefaultClient.Builder()
+ .enableLogging(true)
+ .build()
val account = Auth0.getInstance("{YOUR_CLIENT_ID}", "{YOUR_DOMAIN}")
account.networkingClient = netClient
```
+You can also customize the log level and provide a custom logger:
+
+```kotlin
+val netClient = DefaultClient.Builder()
+ .enableLogging(true)
+ .logLevel(HttpLoggingInterceptor.Level.HEADERS) // NONE, BASIC, HEADERS, or BODY (default)
+ .logger(HttpLoggingInterceptor.Logger { message -> Log.d("Auth0Http", message) })
+ .build()
+```
+
Using Java
```java
-import java.util.HashMap;
-
-DefaultClient netClient = new DefaultClient(
- 10, 10, new HashMap<>() ,true
-);
+DefaultClient netClient = new DefaultClient.Builder()
+ .enableLogging(true)
+ .logLevel(HttpLoggingInterceptor.Level.HEADERS)
+ .build();
Auth0 account = Auth0.getInstance("client id", "domain");
account.setNetworkingClient(netClient);
```
-### Set additional headers for all requests
+
+ Legacy constructor (still supported)
```kotlin
val netClient = DefaultClient(
- defaultHeaders = mapOf("{HEADER-NAME}" to "{HEADER-VALUE}")
+ enableLogging = true
)
+```
+
+
+### Set additional headers for all requests
+
+```kotlin
+val netClient = DefaultClient.Builder()
+ .defaultHeaders(mapOf("{HEADER-NAME}" to "{HEADER-VALUE}"))
+ .build()
val account = Auth0.getInstance("{YOUR_CLIENT_ID}", "{YOUR_DOMAIN}")
account.networkingClient = netClient
@@ -3263,14 +3300,45 @@ account.networkingClient = netClient
Map defaultHeaders = new HashMap<>();
defaultHeaders.put("{HEADER-NAME}", "{HEADER-VALUE}");
-DefaultClient netClient = new DefaultClient(
- 10,10 , defaultHeaders
-);
+DefaultClient netClient = new DefaultClient.Builder()
+ .defaultHeaders(defaultHeaders)
+ .build();
Auth0 account = Auth0.getInstance("client id", "domain");
account.setNetworkingClient(netClient);
```
+
+ Legacy constructor (still supported)
+
+```kotlin
+val netClient = DefaultClient(
+ defaultHeaders = mapOf("{HEADER-NAME}" to "{HEADER-VALUE}")
+)
+```
+
+
+### Custom interceptors
+
+You can add custom OkHttp interceptors to the `DefaultClient` for use cases such as auth token injection, analytics, or certificate pinning:
+
+```kotlin
+val netClient = DefaultClient.Builder()
+ .addInterceptor(Interceptor { chain ->
+ val request = chain.request().newBuilder()
+ .addHeader("X-Request-Id", UUID.randomUUID().toString())
+ .build()
+ chain.proceed(request)
+ })
+ .addInterceptor(myAnalyticsInterceptor)
+ .build()
+
+val account = Auth0.getInstance("{YOUR_CLIENT_ID}", "{YOUR_DOMAIN}")
+account.networkingClient = netClient
+```
+
+Interceptors are invoked in the order they were added, after the built-in retry interceptor and before the logging interceptor.
+
### Advanced configuration
For more advanced configuration of the networking client, you can provide a custom implementation of `NetworkingClient`. This may be useful when you wish to reuse your own networking client, configure a proxy, etc.
diff --git a/V4_MIGRATION_GUIDE.md b/V4_MIGRATION_GUIDE.md
index b8ca744b3..97d80c09c 100644
--- a/V4_MIGRATION_GUIDE.md
+++ b/V4_MIGRATION_GUIDE.md
@@ -96,6 +96,37 @@ 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.
+### DefaultClient.Builder
+
+v4 introduces a `DefaultClient.Builder` for configuring the HTTP client. This replaces the constructor-based approach with a more flexible builder pattern that supports additional options such as write/call timeouts, custom interceptors, and custom loggers.
+
+**v3 (constructor-based — deprecated):**
+
+```kotlin
+// ⚠️ Deprecated: still compiles but shows a warning
+val client = DefaultClient(
+ connectTimeout = 30,
+ readTimeout = 30,
+ enableLogging = true
+)
+```
+
+**v4 (builder pattern — recommended):**
+
+```kotlin
+val client = DefaultClient.Builder()
+ .connectTimeout(30)
+ .readTimeout(30)
+ .writeTimeout(30)
+ .callTimeout(120)
+ .enableLogging(true)
+ .logLevel(HttpLoggingInterceptor.Level.HEADERS)
+ .addInterceptor(myCustomInterceptor)
+ .build()
+```
+
+The legacy constructor is deprecated but **not removed** — existing code will continue to compile and run. Your IDE will show a deprecation warning with a suggested `ReplaceWith` quick-fix to migrate to the Builder.
+
## Getting Help
If you encounter issues during migration:
diff --git a/auth0/src/main/java/com/auth0/android/request/DefaultClient.kt b/auth0/src/main/java/com/auth0/android/request/DefaultClient.kt
index 157f4f6b7..0b1b4d74e 100644
--- a/auth0/src/main/java/com/auth0/android/request/DefaultClient.kt
+++ b/auth0/src/main/java/com/auth0/android/request/DefaultClient.kt
@@ -24,25 +24,187 @@ import javax.net.ssl.X509TrustManager
/**
* Default implementation of a Networking Client.
+ *
+ * Use [DefaultClient.Builder] to create a new instance with custom configuration:
+ *
+ * ```kotlin
+ * val client = DefaultClient.Builder()
+ * .connectTimeout(30)
+ * .readTimeout(30)
+ * .writeTimeout(30)
+ * .enableLogging(true)
+ * .addInterceptor(myInterceptor)
+ * .build()
+ * ```
+ *
+ * The legacy constructor-based API is still supported for backward compatibility.
*/
-public class DefaultClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal constructor(
- connectTimeout: Int,
- readTimeout: Int,
+public class DefaultClient private constructor(
private val defaultHeaders: Map,
- enableLogging: Boolean,
private val gson: Gson,
- sslSocketFactory: SSLSocketFactory?,
- trustManager: X509TrustManager?
+ okHttpClientBuilder: OkHttpClient.Builder
) : NetworkingClient {
/**
- * Create a new DefaultClient.
+ * Builder for creating a [DefaultClient] instance with custom configuration.
*
- * @param connectTimeout the connection timeout, in seconds, to use when executing requests. Default is ten seconds.
- * @param readTimeout the read timeout, in seconds, to use when executing requests. Default is ten seconds.
- * @param defaultHeaders any headers that should be sent on all requests. If a specific request specifies a header with the same key as any header in the default headers, the header specified on the request will take precedence. Default is an empty map.
- * @param enableLogging whether HTTP request and response info should be logged. This should only be set to `true` for debugging purposes in non-production environments, as sensitive information is included in the logs. Defaults to `false`.
+ * Example usage:
+ * ```kotlin
+ * val client = DefaultClient.Builder()
+ * .connectTimeout(30)
+ * .readTimeout(30)
+ * .writeTimeout(30)
+ * .callTimeout(60)
+ * .defaultHeaders(mapOf("X-Custom" to "value"))
+ * .enableLogging(true)
+ * .logLevel(HttpLoggingInterceptor.Level.HEADERS)
+ * .logger(myCustomLogger)
+ * .addInterceptor(myInterceptor)
+ * .build()
+ * ```
*/
+ public class Builder {
+ private var connectTimeout: Int = DEFAULT_TIMEOUT_SECONDS
+ private var readTimeout: Int = DEFAULT_TIMEOUT_SECONDS
+ private var writeTimeout: Int = DEFAULT_TIMEOUT_SECONDS
+ private var callTimeout: Int = 0
+ private var defaultHeaders: Map = mapOf()
+ private var enableLogging: Boolean = false
+ private var logLevel: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.BODY
+ private var logger: HttpLoggingInterceptor.Logger? = null
+ private val interceptors: MutableList = mutableListOf()
+ private var gson: Gson = GsonProvider.gson
+ private var sslSocketFactory: SSLSocketFactory? = null
+ private var trustManager: X509TrustManager? = null
+
+ /**
+ * Sets the connection timeout, in seconds. Default is 10 seconds.
+ */
+ public fun connectTimeout(timeout: Int): Builder = apply { this.connectTimeout = timeout }
+
+ /**
+ * Sets the read timeout, in seconds. Default is 10 seconds.
+ */
+ public fun readTimeout(timeout: Int): Builder = apply { this.readTimeout = timeout }
+
+ /**
+ * Sets the write timeout, in seconds. Default is 10 seconds.
+ */
+ public fun writeTimeout(timeout: Int): Builder = apply { this.writeTimeout = timeout }
+
+ /**
+ * Sets the call timeout, in seconds. Default is 0 (no timeout).
+ * This is an overall timeout that spans the entire call: resolving DNS, connecting,
+ * writing the request body, server processing, and reading the response body.
+ */
+ public fun callTimeout(timeout: Int): Builder = apply { this.callTimeout = timeout }
+
+ /**
+ * Sets default headers to include on all requests. If a specific request specifies
+ * a header with the same key, the request-level header takes precedence.
+ */
+ public fun defaultHeaders(headers: Map): Builder =
+ apply { this.defaultHeaders = headers }
+
+ /**
+ * Enables or disables HTTP logging. Should only be set to `true` for debugging
+ * in non-production environments, as sensitive information may be logged.
+ * Defaults to `false`.
+ */
+ public fun enableLogging(enable: Boolean): Builder = apply { this.enableLogging = enable }
+
+ /**
+ * Sets the log level for the HTTP logging interceptor.
+ * Only takes effect if [enableLogging] is set to `true`.
+ * Default is [HttpLoggingInterceptor.Level.BODY].
+ */
+ public fun logLevel(level: HttpLoggingInterceptor.Level): Builder =
+ apply { this.logLevel = level }
+
+ /**
+ * Sets a custom logger for the HTTP logging interceptor.
+ * Only takes effect if [enableLogging] is set to `true`.
+ * If not set, the default [HttpLoggingInterceptor.Logger] (which logs to logcat) is used.
+ */
+ public fun logger(logger: HttpLoggingInterceptor.Logger): Builder =
+ apply { this.logger = logger }
+
+ /**
+ * Adds a custom OkHttp [Interceptor]. Multiple interceptors can be added
+ * by calling this method multiple times. They are invoked in the order they were added,
+ * after the built-in [RetryInterceptor] and before the logging interceptor.
+ */
+ public fun addInterceptor(interceptor: Interceptor): Builder =
+ apply { this.interceptors.add(interceptor) }
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal fun gson(gson: Gson): Builder = apply { this.gson = gson }
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal fun sslSocketFactory(
+ sslSocketFactory: SSLSocketFactory,
+ trustManager: X509TrustManager
+ ): Builder = apply {
+ this.sslSocketFactory = sslSocketFactory
+ this.trustManager = trustManager
+ }
+
+ /**
+ * Builds a new [DefaultClient] instance with the configured options.
+ */
+ public fun build(): DefaultClient {
+ val okBuilder = OkHttpClient.Builder()
+
+ okBuilder.addInterceptor(RetryInterceptor())
+
+ interceptors.forEach { okBuilder.addInterceptor(it) }
+
+ if (enableLogging) {
+ val loggingInterceptor = if (logger != null) {
+ HttpLoggingInterceptor(logger!!)
+ } else {
+ HttpLoggingInterceptor()
+ }
+ loggingInterceptor.setLevel(logLevel)
+ okBuilder.addInterceptor(loggingInterceptor)
+ }
+
+ okBuilder.connectTimeout(connectTimeout.toLong(), TimeUnit.SECONDS)
+ okBuilder.readTimeout(readTimeout.toLong(), TimeUnit.SECONDS)
+ okBuilder.writeTimeout(writeTimeout.toLong(), TimeUnit.SECONDS)
+ okBuilder.callTimeout(callTimeout.toLong(), TimeUnit.SECONDS)
+
+ val ssl = sslSocketFactory
+ val tm = trustManager
+ if (ssl != null && tm != null) {
+ okBuilder.sslSocketFactory(ssl, tm)
+ }
+
+ return DefaultClient(defaultHeaders, gson, okBuilder)
+ }
+ }
+
+ /**
+ * Create a new DefaultClient with default configuration.
+ *
+ * For more configuration options, use [DefaultClient.Builder].
+ *
+ * @param connectTimeout the connection timeout, in seconds. Default is 10 seconds.
+ * @param readTimeout the read timeout, in seconds. Default is 10 seconds.
+ * @param defaultHeaders headers to include on all requests. Default is an empty map.
+ * @param enableLogging whether to log HTTP request/response info. Defaults to `false`.
+ */
+ @Deprecated(
+ message = "Use DefaultClient.Builder() for more configuration options.",
+ replaceWith = ReplaceWith(
+ "DefaultClient.Builder()" +
+ ".connectTimeout(connectTimeout)" +
+ ".readTimeout(readTimeout)" +
+ ".defaultHeaders(defaultHeaders)" +
+ ".enableLogging(enableLogging)" +
+ ".build()"
+ )
+ )
@JvmOverloads
public constructor(
connectTimeout: Int = DEFAULT_TIMEOUT_SECONDS,
@@ -50,13 +212,44 @@ public class DefaultClient @VisibleForTesting(otherwise = VisibleForTesting.PRIV
defaultHeaders: Map = mapOf(),
enableLogging: Boolean = false,
) : this(
- connectTimeout,
- readTimeout,
- defaultHeaders,
- enableLogging,
- GsonProvider.gson,
- null,
- null
+ defaultHeaders = defaultHeaders,
+ gson = GsonProvider.gson,
+ okHttpClientBuilder = OkHttpClient.Builder().apply {
+ addInterceptor(RetryInterceptor())
+ if (enableLogging) {
+ addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
+ }
+ connectTimeout(connectTimeout.toLong(), TimeUnit.SECONDS)
+ readTimeout(readTimeout.toLong(), TimeUnit.SECONDS)
+ }
+ )
+
+ /**
+ * Internal constructor used by tests to inject SSL and Gson.
+ */
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal constructor(
+ connectTimeout: Int,
+ readTimeout: Int,
+ defaultHeaders: Map,
+ enableLogging: Boolean,
+ gson: Gson,
+ sslSocketFactory: SSLSocketFactory?,
+ trustManager: X509TrustManager?
+ ) : this(
+ defaultHeaders = defaultHeaders,
+ gson = gson,
+ okHttpClientBuilder = OkHttpClient.Builder().apply {
+ addInterceptor(RetryInterceptor())
+ if (enableLogging) {
+ addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
+ }
+ connectTimeout(connectTimeout.toLong(), TimeUnit.SECONDS)
+ readTimeout(readTimeout.toLong(), TimeUnit.SECONDS)
+ if (sslSocketFactory != null && trustManager != null) {
+ sslSocketFactory(sslSocketFactory, trustManager)
+ }
+ }
)
@get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
@@ -125,35 +318,14 @@ public class DefaultClient @VisibleForTesting(otherwise = VisibleForTesting.PRIV
}
init {
- val builder = OkHttpClient.Builder()
- // Add retry interceptor
- builder.addInterceptor(RetryInterceptor())
-
- // logging
- if (enableLogging) {
- val logger: Interceptor = HttpLoggingInterceptor()
- .setLevel(HttpLoggingInterceptor.Level.BODY)
- builder.addInterceptor(logger)
- }
+ okHttpClient = okHttpClientBuilder.build()
- // timeouts
- builder.connectTimeout(connectTimeout.toLong(), TimeUnit.SECONDS)
- builder.readTimeout(readTimeout.toLong(), TimeUnit.SECONDS)
-
- // testing with ssl hook (internal constructor params visibility only)
- if (sslSocketFactory != null && trustManager != null) {
- builder.sslSocketFactory(sslSocketFactory, trustManager)
- }
-
- okHttpClient = builder.build()
-
- // Non-retryable client for DPoP requests
+ // Non-retryable client for DPoP requests — inherits all configuration
nonRetryableOkHttpClient = okHttpClient.newBuilder()
.retryOnConnectionFailure(false)
.build()
}
-
internal companion object {
const val DEFAULT_TIMEOUT_SECONDS: Int = 10
val APPLICATION_JSON_UTF8: MediaType =
diff --git a/auth0/src/test/java/com/auth0/android/provider/WebAuthProviderTest.kt b/auth0/src/test/java/com/auth0/android/provider/WebAuthProviderTest.kt
index 9eea3b9e2..94baa6b3f 100644
--- a/auth0/src/test/java/com/auth0/android/provider/WebAuthProviderTest.kt
+++ b/auth0/src/test/java/com/auth0/android/provider/WebAuthProviderTest.kt
@@ -1169,6 +1169,7 @@ public class WebAuthProviderTest {
@Test
@Throws(Exception::class)
+ @Suppress("DEPRECATION")
public fun shouldResumeLoginWithCustomNetworkingClient() {
val networkingClient: NetworkingClient = Mockito.spy(DefaultClient())
val authCallback = mock>()
diff --git a/auth0/src/test/java/com/auth0/android/request/DefaultClientTest.kt b/auth0/src/test/java/com/auth0/android/request/DefaultClientTest.kt
index 7a71a70bf..0db1c95a0 100644
--- a/auth0/src/test/java/com/auth0/android/request/DefaultClientTest.kt
+++ b/auth0/src/test/java/com/auth0/android/request/DefaultClientTest.kt
@@ -81,6 +81,7 @@ public class DefaultClientTest {
}
@Test
+ @Suppress("DEPRECATION")
public fun shouldHaveLoggingDisabledByDefault() {
val netClient = DefaultClient(enableLogging = false)
assertThat(netClient.okHttpClient.interceptors, hasSize(1))
@@ -91,6 +92,7 @@ public class DefaultClientTest {
}
@Test
+ @Suppress("DEPRECATION")
public fun shouldHaveRetryInterceptorEnabled() {
val netClient = DefaultClient(enableLogging = false)
assertThat(netClient.okHttpClient.interceptors, hasSize(1))
@@ -101,6 +103,7 @@ public class DefaultClientTest {
}
@Test
+ @Suppress("DEPRECATION")
public fun shouldHaveLoggingEnabledIfSpecified() {
val netClient = DefaultClient(enableLogging = true)
assertThat(netClient.okHttpClient.interceptors, hasSize(2))
@@ -113,6 +116,7 @@ public class DefaultClientTest {
}
@Test
+ @Suppress("DEPRECATION")
public fun shouldHaveDefaultTimeoutValues() {
val client = DefaultClient()
assertThat(client.okHttpClient.connectTimeoutMillis, equalTo(10 * 1000))
@@ -120,6 +124,7 @@ public class DefaultClientTest {
}
@Test
+ @Suppress("DEPRECATION")
public fun shouldUseTimeoutConfigIfSpecified() {
val client = DefaultClient(connectTimeout = 100, readTimeout = 200)
assertThat(client.okHttpClient.connectTimeoutMillis, equalTo(100 * 1000))
@@ -353,14 +358,283 @@ public class DefaultClientTest {
}
private fun createDefaultClientForTest(defaultHeaders: Map): DefaultClient {
- return DefaultClient(
- defaultHeaders = defaultHeaders,
- readTimeout = 10,
- connectTimeout = 10,
- enableLogging = false,
- gson = gson,
- sslSocketFactory = SSLTestUtils.clientCertificates.sslSocketFactory(),
- trustManager = SSLTestUtils.clientCertificates.trustManager
+ return DefaultClient.Builder()
+ .connectTimeout(10)
+ .readTimeout(10)
+ .defaultHeaders(defaultHeaders)
+ .enableLogging(false)
+ .gson(gson)
+ .sslSocketFactory(
+ SSLTestUtils.clientCertificates.sslSocketFactory(),
+ SSLTestUtils.clientCertificates.trustManager
+ )
+ .build()
+ }
+
+ @Test
+ public fun builderShouldCreateClientWithDefaultValues() {
+ val client = DefaultClient.Builder().build()
+ assertThat(client.okHttpClient.connectTimeoutMillis, equalTo(10 * 1000))
+ assertThat(client.okHttpClient.readTimeoutMillis, equalTo(10 * 1000))
+ assertThat(client.okHttpClient.writeTimeoutMillis, equalTo(10 * 1000))
+ assertThat(client.okHttpClient.callTimeoutMillis, equalTo(0))
+ assertThat(client.okHttpClient.interceptors, hasSize(1))
+ assertThat(client.okHttpClient.interceptors[0] is RetryInterceptor, equalTo(true))
+ }
+
+ @Test
+ public fun builderShouldSetConnectTimeout() {
+ val client = DefaultClient.Builder()
+ .connectTimeout(30)
+ .build()
+ assertThat(client.okHttpClient.connectTimeoutMillis, equalTo(30 * 1000))
+ }
+
+ @Test
+ public fun builderShouldSetReadTimeout() {
+ val client = DefaultClient.Builder()
+ .readTimeout(45)
+ .build()
+ assertThat(client.okHttpClient.readTimeoutMillis, equalTo(45 * 1000))
+ }
+
+ @Test
+ public fun builderShouldSetWriteTimeout() {
+ val client = DefaultClient.Builder()
+ .writeTimeout(20)
+ .build()
+ assertThat(client.okHttpClient.writeTimeoutMillis, equalTo(20 * 1000))
+ }
+
+ @Test
+ public fun builderShouldSetCallTimeout() {
+ val client = DefaultClient.Builder()
+ .callTimeout(60)
+ .build()
+ assertThat(client.okHttpClient.callTimeoutMillis, equalTo(60 * 1000))
+ }
+
+ @Test
+ public fun builderShouldSetAllTimeouts() {
+ val client = DefaultClient.Builder()
+ .connectTimeout(15)
+ .readTimeout(25)
+ .writeTimeout(35)
+ .callTimeout(120)
+ .build()
+ assertThat(client.okHttpClient.connectTimeoutMillis, equalTo(15 * 1000))
+ assertThat(client.okHttpClient.readTimeoutMillis, equalTo(25 * 1000))
+ assertThat(client.okHttpClient.writeTimeoutMillis, equalTo(35 * 1000))
+ assertThat(client.okHttpClient.callTimeoutMillis, equalTo(120 * 1000))
+ }
+
+ @Test
+ public fun builderShouldEnableLoggingWithDefaultLevel() {
+ val client = DefaultClient.Builder()
+ .enableLogging(true)
+ .build()
+ assertThat(client.okHttpClient.interceptors, hasSize(2))
+ val loggingInterceptor = client.okHttpClient.interceptors[1] as HttpLoggingInterceptor
+ assertThat(loggingInterceptor.level, equalTo(HttpLoggingInterceptor.Level.BODY))
+ }
+
+ @Test
+ public fun builderShouldSetCustomLogLevel() {
+ val client = DefaultClient.Builder()
+ .enableLogging(true)
+ .logLevel(HttpLoggingInterceptor.Level.HEADERS)
+ .build()
+ assertThat(client.okHttpClient.interceptors, hasSize(2))
+ val loggingInterceptor = client.okHttpClient.interceptors[1] as HttpLoggingInterceptor
+ assertThat(loggingInterceptor.level, equalTo(HttpLoggingInterceptor.Level.HEADERS))
+ }
+
+ @Test
+ public fun builderShouldNotAddLoggingInterceptorWhenDisabled() {
+ val client = DefaultClient.Builder()
+ .enableLogging(false)
+ .logLevel(HttpLoggingInterceptor.Level.HEADERS)
+ .build()
+ assertThat(client.okHttpClient.interceptors, hasSize(1))
+ assertThat(client.okHttpClient.interceptors[0] is RetryInterceptor, equalTo(true))
+ }
+
+ @Test
+ public fun builderShouldSetCustomLogger() {
+ val logs = mutableListOf()
+ val customLogger = HttpLoggingInterceptor.Logger { message -> logs.add(message) }
+
+ val client = DefaultClient.Builder()
+ .enableLogging(true)
+ .logger(customLogger)
+ .sslSocketFactory(
+ SSLTestUtils.clientCertificates.sslSocketFactory(),
+ SSLTestUtils.clientCertificates.trustManager
+ )
+ .build()
+
+ assertThat(client.okHttpClient.interceptors, hasSize(2))
+ assertThat(client.okHttpClient.interceptors[1] is HttpLoggingInterceptor, equalTo(true))
+
+ enqueueMockResponse(STATUS_SUCCESS, JSON_OK)
+ executeRequest(HttpMethod.GET, client)
+ assertThat(logs.isEmpty(), equalTo(false))
+ }
+
+ @Test
+ public fun builderShouldAddSingleCustomInterceptor() {
+ var intercepted = false
+ val customInterceptor = Interceptor { chain ->
+ intercepted = true
+ chain.proceed(chain.request())
+ }
+
+ val client = DefaultClient.Builder()
+ .addInterceptor(customInterceptor)
+ .sslSocketFactory(
+ SSLTestUtils.clientCertificates.sslSocketFactory(),
+ SSLTestUtils.clientCertificates.trustManager
+ )
+ .build()
+
+ assertThat(client.okHttpClient.interceptors, hasSize(2))
+ assertThat(client.okHttpClient.interceptors[0] is RetryInterceptor, equalTo(true))
+
+ enqueueMockResponse(STATUS_SUCCESS, JSON_OK)
+ executeRequest(HttpMethod.GET, client)
+ assertThat(intercepted, equalTo(true))
+ }
+
+ @Test
+ public fun builderShouldAddMultipleCustomInterceptors() {
+ val callOrder = mutableListOf()
+ val firstInterceptor = Interceptor { chain ->
+ callOrder.add("first")
+ chain.proceed(chain.request())
+ }
+ val secondInterceptor = Interceptor { chain ->
+ callOrder.add("second")
+ chain.proceed(chain.request())
+ }
+
+ val client = DefaultClient.Builder()
+ .addInterceptor(firstInterceptor)
+ .addInterceptor(secondInterceptor)
+ .sslSocketFactory(
+ SSLTestUtils.clientCertificates.sslSocketFactory(),
+ SSLTestUtils.clientCertificates.trustManager
+ )
+ .build()
+
+ assertThat(client.okHttpClient.interceptors, hasSize(3))
+
+ enqueueMockResponse(STATUS_SUCCESS, JSON_OK)
+ executeRequest(HttpMethod.GET, client)
+ assertThat(callOrder, equalTo(listOf("first", "second")))
+ }
+
+ @Test
+ public fun builderShouldPlaceCustomInterceptorsBeforeLogging() {
+ val callOrder = mutableListOf()
+ val customInterceptor = Interceptor { chain ->
+ callOrder.add("custom")
+ chain.proceed(chain.request())
+ }
+ val customLogger = HttpLoggingInterceptor.Logger { callOrder.add("logging") }
+
+ val client = DefaultClient.Builder()
+ .addInterceptor(customInterceptor)
+ .enableLogging(true)
+ .logger(customLogger)
+ .sslSocketFactory(
+ SSLTestUtils.clientCertificates.sslSocketFactory(),
+ SSLTestUtils.clientCertificates.trustManager
+ )
+ .build()
+
+ assertThat(client.okHttpClient.interceptors, hasSize(3))
+ assertThat(client.okHttpClient.interceptors[0] is RetryInterceptor, equalTo(true))
+ assertThat(client.okHttpClient.interceptors[2] is HttpLoggingInterceptor, equalTo(true))
+
+ enqueueMockResponse(STATUS_SUCCESS, JSON_OK)
+ executeRequest(HttpMethod.GET, client)
+ val customIndex = callOrder.indexOf("custom")
+ val loggingIndex = callOrder.indexOf("logging")
+ assertThat(customIndex, not(equalTo(-1)))
+ assertThat(loggingIndex, not(equalTo(-1)))
+ assertThat(customIndex < loggingIndex, equalTo(true))
+ }
+
+ @Test
+ public fun builderShouldSetDefaultHeaders() {
+ enqueueMockResponse(STATUS_SUCCESS, JSON_OK)
+ val client = DefaultClient.Builder()
+ .defaultHeaders(mapOf("x-custom" to "test-value"))
+ .sslSocketFactory(
+ SSLTestUtils.clientCertificates.sslSocketFactory(),
+ SSLTestUtils.clientCertificates.trustManager
+ )
+ .build()
+
+ executeRequest(HttpMethod.GET, client)
+ val sentRequest = mockServer.takeRequest()
+ requestAssertions(sentRequest, HttpMethod.GET, mapOf("x-custom" to "test-value"))
+ }
+
+ @Test
+ public fun builderNonRetryableClientShouldInheritConfiguration() {
+ val customInterceptor = Interceptor { chain -> chain.proceed(chain.request()) }
+ val client = DefaultClient.Builder()
+ .connectTimeout(25)
+ .readTimeout(35)
+ .writeTimeout(45)
+ .addInterceptor(customInterceptor)
+ .enableLogging(true)
+ .build()
+
+ assertThat(
+ client.nonRetryableOkHttpClient.connectTimeoutMillis,
+ equalTo(client.okHttpClient.connectTimeoutMillis)
+ )
+ assertThat(
+ client.nonRetryableOkHttpClient.readTimeoutMillis,
+ equalTo(client.okHttpClient.readTimeoutMillis)
+ )
+ assertThat(
+ client.nonRetryableOkHttpClient.writeTimeoutMillis,
+ equalTo(client.okHttpClient.writeTimeoutMillis)
+ )
+ assertThat(
+ client.nonRetryableOkHttpClient.interceptors.size,
+ equalTo(client.okHttpClient.interceptors.size)
+ )
+ assertThat(client.okHttpClient.retryOnConnectionFailure, equalTo(true))
+ assertThat(client.nonRetryableOkHttpClient.retryOnConnectionFailure, equalTo(false))
+ }
+
+ @Test
+ @Suppress("DEPRECATION")
+ public fun legacyConstructorShouldStillWork() {
+ val client = DefaultClient()
+ assertThat(client.okHttpClient.connectTimeoutMillis, equalTo(10 * 1000))
+ assertThat(client.okHttpClient.readTimeoutMillis, equalTo(10 * 1000))
+ assertThat(client.okHttpClient.interceptors, hasSize(1))
+ assertThat(client.okHttpClient.interceptors[0] is RetryInterceptor, equalTo(true))
+ }
+
+ @Test
+ @Suppress("DEPRECATION")
+ public fun legacyConstructorWithParamsShouldStillWork() {
+ val client = DefaultClient(
+ connectTimeout = 30,
+ readTimeout = 45,
+ defaultHeaders = mapOf("X-Test" to "value"),
+ enableLogging = true
)
+ assertThat(client.okHttpClient.connectTimeoutMillis, equalTo(30 * 1000))
+ assertThat(client.okHttpClient.readTimeoutMillis, equalTo(45 * 1000))
+ assertThat(client.okHttpClient.interceptors, hasSize(2))
+ assertThat(client.okHttpClient.interceptors[0] is RetryInterceptor, equalTo(true))
+ assertThat(client.okHttpClient.interceptors[1] is HttpLoggingInterceptor, equalTo(true))
}
}
\ No newline at end of file
diff --git a/auth0/src/test/java/com/auth0/android/util/SSLTestUtils.kt b/auth0/src/test/java/com/auth0/android/util/SSLTestUtils.kt
index 542a8e4b6..897d71123 100644
--- a/auth0/src/test/java/com/auth0/android/util/SSLTestUtils.kt
+++ b/auth0/src/test/java/com/auth0/android/util/SSLTestUtils.kt
@@ -31,15 +31,17 @@ internal object SSLTestUtils {
.heldCertificate(localhostCertificate)
.build()
- testClient = DefaultClient(
- defaultHeaders = mapOf(),
- readTimeout = 10,
- connectTimeout = 10,
- enableLogging = false,
- gson = GsonProvider.gson,
- sslSocketFactory = clientCertificates.sslSocketFactory(),
- trustManager = clientCertificates.trustManager
- )
+ testClient = DefaultClient.Builder()
+ .connectTimeout(10)
+ .readTimeout(10)
+ .defaultHeaders(mapOf())
+ .enableLogging(false)
+ .gson(GsonProvider.gson)
+ .sslSocketFactory(
+ clientCertificates.sslSocketFactory(),
+ clientCertificates.trustManager
+ )
+ .build()
}
fun createMockWebServer(): MockWebServer {
diff --git a/sample/src/main/java/com/auth0/sample/DatabaseLoginFragment.kt b/sample/src/main/java/com/auth0/sample/DatabaseLoginFragment.kt
index 918de531b..c4e54212a 100644
--- a/sample/src/main/java/com/auth0/sample/DatabaseLoginFragment.kt
+++ b/sample/src/main/java/com/auth0/sample/DatabaseLoginFragment.kt
@@ -59,7 +59,9 @@ class DatabaseLoginFragment : Fragment() {
getString(R.string.com_auth0_domain)
)
// Only enable network traffic logging on production environments!
- account.networkingClient = DefaultClient(enableLogging = true)
+ account.networkingClient = DefaultClient.Builder()
+ .enableLogging(true)
+ .build()
account
}