2525 * API clients.
2626 * </p>
2727 * <p>
28- * For most use cases, usage of this client is recommended. If you have more advanced use cases,
29- * such as the need to re-use an existing HTTP client, you may consider providing a custom
30- * implementation of {@link Auth0HttpClient}.
28+ * For most use cases, usage of this client is recommended. To reuse an existing {@link OkHttpClient}
29+ * and its transport configuration, use {@link Builder#withClient(OkHttpClient)}. Only for advanced use
30+ * cases not covered by the {@link Builder} should you provide a custom implementation of
31+ * {@link Auth0HttpClient}.
3132 * </p>
3233 */
3334public class DefaultHttpClient implements Auth0HttpClient {
@@ -55,15 +56,30 @@ OkHttpClient getOkClient() {
5556 }
5657
5758 private DefaultHttpClient (Builder builder ) {
58- okhttp3 .OkHttpClient .Builder clientBuilder = new okhttp3 .OkHttpClient .Builder ();
59- clientBuilder .readTimeout (sanitizeTimeout (builder .readTimeout ), TimeUnit .SECONDS );
60- clientBuilder .connectTimeout (sanitizeTimeout (builder .connectTimeout ), TimeUnit .SECONDS );
59+ okhttp3 .OkHttpClient .Builder clientBuilder ;
60+ if (builder .baseClient != null ) {
61+ // A caller-supplied client owns all transport configuration: timeouts, dispatcher, connection
62+ // pool, cache, proxy, and any interceptors already registered on it are used as-is. The transport
63+ // settings on this builder (timeouts, dispatcher, proxy) are intentionally NOT applied here, so
64+ // they never silently override the caller's client. The SDK's behavior interceptors are still
65+ // layered on below.
66+ clientBuilder = builder .baseClient .newBuilder ();
67+ } else {
68+ // Default path (unchanged): the SDK builds and fully configures the transport.
69+ clientBuilder = new okhttp3 .OkHttpClient .Builder ();
70+ clientBuilder .readTimeout (sanitizeTimeout (builder .readTimeout ), TimeUnit .SECONDS );
71+ clientBuilder .connectTimeout (sanitizeTimeout (builder .connectTimeout ), TimeUnit .SECONDS );
72+ clientBuilder .dispatcher (getDispatcher (builder .maxRequests , builder .maxRequestsPerHost ));
73+ configureProxy (clientBuilder , builder .proxyOptions );
74+ }
75+
76+ // SDK behavior is always applied regardless of the transport client, so Auth0 telemetry, rate-limit
77+ // handling, and logging are guaranteed. These interceptors are parameterized by this builder
78+ // (withTelemetry/withLogging/withMaxRetries), which remain effective even when a base client is used.
6179 clientBuilder .addInterceptor (getLoggingInterceptor (builder .loggingOptions ));
6280 clientBuilder .addInterceptor (getTelemetryInterceptor (builder .telemetryEnabled , builder .telemetry ));
6381 clientBuilder .addInterceptor (getRateLimitInterceptor (builder .maxRetries ));
64- clientBuilder .dispatcher (getDispatcher (builder .maxRequests , builder .maxRequestsPerHost ));
6582
66- configureProxy (clientBuilder , builder .proxyOptions );
6783 this .client = clientBuilder .build ();
6884 }
6985
@@ -288,13 +304,15 @@ public static class Builder {
288304 private int maxRetries = 3 ;
289305 private int maxRequests = 64 ;
290306 private int maxRequestsPerHost = 5 ;
307+ private OkHttpClient baseClient ;
291308
292309 /**
293310 * Sets the value of the read timeout, in seconds. Defaults to ten seconds. A value of zero results in no read timeout.
294311 * Negative numbers will be treated as zero.
295312 *
296313 * @param readTimeout the value of the read timeout to use.
297314 * @return this builder instance.
315+ * @see #withClient(OkHttpClient) ignored when a base client is supplied.
298316 */
299317 public Builder withReadTimeout (int readTimeout ) {
300318 this .readTimeout = readTimeout ;
@@ -306,6 +324,7 @@ public Builder withReadTimeout(int readTimeout) {
306324 * Negative numbers will be treated as zero.
307325 * @param connectTimeout the value of the connect timeout to use.
308326 * @return this builder instance.
327+ * @see #withClient(OkHttpClient) ignored when a base client is supplied.
309328 */
310329 public Builder withConnectTimeout (int connectTimeout ) {
311330 this .connectTimeout = connectTimeout ;
@@ -327,6 +346,7 @@ public Builder withLogging(LoggingOptions loggingOptions) {
327346 *
328347 * @param proxyOptions the Proxy configuration options
329348 * @return this builder instance.
349+ * @see #withClient(OkHttpClient) ignored when a base client is supplied.
330350 */
331351 public Builder withProxy (ProxyOptions proxyOptions ) {
332352 this .proxyOptions = proxyOptions ;
@@ -381,6 +401,7 @@ public Builder withMaxRetries(int maxRetries) {
381401 *
382402 * @param maxRequests the number of requests to execute concurrently. Must be equal to or greater than one.
383403 * @return this builder instance.
404+ * @see #withClient(OkHttpClient) ignored when a base client is supplied.
384405 */
385406 public Builder withMaxRequests (int maxRequests ) {
386407 this .maxRequests = maxRequests ;
@@ -392,12 +413,42 @@ public Builder withMaxRequests(int maxRequests) {
392413 *
393414 * @param maxRequestsPerHost the maximum number of requests for each host to execute concurrently. Must be equal to or greater than one.
394415 * @return this builder instance.
416+ * @see #withClient(OkHttpClient) ignored when a base client is supplied.
395417 */
396418 public Builder withMaxRequestsPerHost (int maxRequestsPerHost ) {
397419 this .maxRequestsPerHost = maxRequestsPerHost ;
398420 return this ;
399421 }
400422
423+ /**
424+ * Use an existing {@link OkHttpClient} as the base for this client, reusing all of its
425+ * <strong>transport</strong> configuration as-is: timeouts, dispatcher, connection pool, cache,
426+ * proxy, and any interceptors already registered on it.
427+ * <p>
428+ * When a base client is provided, the transport-related settings on this builder
429+ * ({@link #withReadTimeout(int)}, {@link #withConnectTimeout(int)}, {@link #withMaxRequests(int)},
430+ * {@link #withMaxRequestsPerHost(int)}, and {@link #withProxy(ProxyOptions)}) are
431+ * <strong>ignored</strong>. This is deliberate: your client's configuration is never silently
432+ * overridden. Configuring those concerns is your responsibility, on the {@code OkHttpClient} you
433+ * supply.
434+ * </p>
435+ * <p>
436+ * The SDK's own behavior is always layered on top and cannot be bypassed: the Auth0 telemetry,
437+ * rate-limit handling, and logging interceptors are added to your client. These remain configurable
438+ * via {@link #withTelemetry(String, String)}, {@link #telemetryEnabled(boolean)},
439+ * {@link #withMaxRetries(int)}, and {@link #withLogging(LoggingOptions)}, which stay effective even
440+ * when a base client is used.
441+ * </p>
442+ *
443+ * @param baseClient the {@link OkHttpClient} whose transport configuration should be reused.
444+ * @return this builder instance.
445+ */
446+ public Builder withClient (OkHttpClient baseClient ) {
447+ Asserts .assertNotNull (baseClient , "base client" );
448+ this .baseClient = baseClient ;
449+ return this ;
450+ }
451+
401452 /**
402453 * Create a {@code DefaultHttpClient} from this configured builder.
403454 * @return the created {@code DefaultHttpClient}.
0 commit comments