From 79f74dabb9a1e7943ff3177c7085fca9aa4ddc86 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Fri, 14 Aug 2026 17:28:41 +0530 Subject: [PATCH 1/4] feat: allow custom telemetry for SDKs built on auth0-java --- .../client/mgmt/ManagementApiBuilder.java | 22 ++++++++ .../auth0/client/mgmt/core/ClientOptions.java | 32 ++++++++--- .../auth0/net/client/DefaultHttpClient.java | 26 ++++++++- .../com/auth0/client/auth/AuthAPITest.java | 38 +++++++++++++ .../mgmt/ManagementApiTelemetryTest.java | 53 +++++++++++++++++++ 5 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java diff --git a/src/main/java/com/auth0/client/mgmt/ManagementApiBuilder.java b/src/main/java/com/auth0/client/mgmt/ManagementApiBuilder.java index 479fba5ab..9e59bd75a 100644 --- a/src/main/java/com/auth0/client/mgmt/ManagementApiBuilder.java +++ b/src/main/java/com/auth0/client/mgmt/ManagementApiBuilder.java @@ -4,6 +4,7 @@ package com.auth0.client.mgmt; import com.auth0.client.mgmt.core.*; +import com.auth0.net.Telemetry; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -27,6 +28,8 @@ public class ManagementApiBuilder { private String customDomain = null; + private Telemetry telemetry = null; + // Domain-based initialization fields private String domain = null; private String clientId = null; @@ -188,6 +191,22 @@ public ManagementApiBuilder addHeader(String name, String value) { return this; } + /** + * Configure the telemetry sent to Auth0 on every request. Use this when building an SDK on top of + * auth0-java so that requests are attributed to the wrapping library, with auth0-java reported as the + * underlying library in the telemetry environment. + * + *

If not set, telemetry defaults to identifying this library as {@code auth0-java}. + * + * @param name The name of the library sending the requests (e.g. the wrapping SDK's name) + * @param version The version of the library sending the requests + * @return This builder for method chaining + */ + public ManagementApiBuilder withTelemetry(String name, String version) { + this.telemetry = new Telemetry(name, version, Telemetry.class.getPackage().getImplementationVersion()); + return this; + } + protected ClientOptions buildClientOptions() { ClientOptions.Builder builder = ClientOptions.builder(); setEnvironment(builder); @@ -203,6 +222,9 @@ protected ClientOptions buildClientOptions() { builder.addHeader(CustomDomainInterceptor.HEADER_NAME, this.customDomain); builder.addInterceptor(new CustomDomainInterceptor()); } + if (this.telemetry != null) { + builder.telemetry(this.telemetry); + } setAdditional(builder); return builder.build(); } diff --git a/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java b/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java index 82886a4b4..f244ff7e6 100644 --- a/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java +++ b/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java @@ -33,15 +33,17 @@ private ClientOptions( Map> headerSuppliers, OkHttpClient httpClient, int timeout, - int maxRetries) { + int maxRetries, + Telemetry telemetry) { this.environment = environment; this.headers = new HashMap<>(); this.headers.putAll(headers); - Telemetry telemetry = - new Telemetry("auth0-java", Telemetry.class.getPackage().getImplementationVersion()); - if (telemetry.getValue() != null) { - this.headers.put("Auth0-Client", telemetry.getValue()); + Telemetry resolvedTelemetry = telemetry != null + ? telemetry + : new Telemetry("auth0-java", Telemetry.class.getPackage().getImplementationVersion()); + if (resolvedTelemetry.getValue() != null) { + this.headers.put("Auth0-Client", resolvedTelemetry.getValue()); } this.headerSuppliers = headerSuppliers; this.httpClient = httpClient; @@ -113,6 +115,8 @@ public static class Builder { private LogConfig logging = null; + private Telemetry telemetry = null; + public Builder environment(Environment environment) { this.environment = environment; return this; @@ -173,6 +177,16 @@ public Builder addInterceptor(Interceptor interceptor) { return this; } + /** + * Configure the telemetry sent to Auth0 on every request. Used when building an SDK on top of + * auth0-java so requests are attributed to the wrapping library. If not set, telemetry defaults + * to identifying this library as {@code auth0-java}. + */ + public Builder telemetry(Telemetry telemetry) { + this.telemetry = telemetry; + return this; + } + public ClientOptions build() { OkHttpClient.Builder httpClientBuilder = this.httpClient != null ? this.httpClient.newBuilder() : new OkHttpClient.Builder(); @@ -205,7 +219,13 @@ public ClientOptions build() { this.timeout = Optional.of(httpClient.callTimeoutMillis() / 1000); return new ClientOptions( - environment, headers, headerSuppliers, httpClient, this.timeout.get(), this.maxRetries); + environment, + headers, + headerSuppliers, + httpClient, + this.timeout.get(), + this.maxRetries, + this.telemetry); } /** diff --git a/src/main/java/com/auth0/net/client/DefaultHttpClient.java b/src/main/java/com/auth0/net/client/DefaultHttpClient.java index d6bb8d0d1..af3422f91 100644 --- a/src/main/java/com/auth0/net/client/DefaultHttpClient.java +++ b/src/main/java/com/auth0/net/client/DefaultHttpClient.java @@ -3,6 +3,7 @@ import com.auth0.client.LoggingOptions; import com.auth0.client.ProxyOptions; import com.auth0.net.RateLimitInterceptor; +import com.auth0.net.Telemetry; import com.auth0.net.TelemetryInterceptor; import java.io.IOException; import java.util.HashMap; @@ -57,7 +58,7 @@ private DefaultHttpClient(Builder builder) { clientBuilder.readTimeout(sanitizeTimeout(builder.readTimeout), TimeUnit.SECONDS); clientBuilder.connectTimeout(sanitizeTimeout(builder.connectTimeout), TimeUnit.SECONDS); clientBuilder.addInterceptor(getLoggingInterceptor(builder.loggingOptions)); - clientBuilder.addInterceptor(getTelemetryInterceptor(builder.telemetryEnabled)); + clientBuilder.addInterceptor(getTelemetryInterceptor(builder.telemetryEnabled, builder.telemetry)); clientBuilder.addInterceptor(getRateLimitInterceptor(builder.maxRetries)); clientBuilder.dispatcher(getDispatcher(builder.maxRequests, builder.maxRequestsPerHost)); @@ -243,8 +244,11 @@ public okhttp3.Request authenticate(Route route, @NotNull Response response) { } } - private TelemetryInterceptor getTelemetryInterceptor(boolean telemetryEnabled) { + private TelemetryInterceptor getTelemetryInterceptor(boolean telemetryEnabled, Telemetry telemetry) { TelemetryInterceptor interceptor = new TelemetryInterceptor(); + if (telemetry != null) { + interceptor.setTelemetry(telemetry); + } interceptor.setEnabled(telemetryEnabled); return interceptor; } @@ -279,6 +283,7 @@ public static class Builder { private ProxyOptions proxyOptions; private LoggingOptions loggingOptions; private boolean telemetryEnabled = true; + private Telemetry telemetry; private int maxRetries = 3; private int maxRequests = 64; private int maxRequestsPerHost = 5; @@ -337,6 +342,23 @@ public Builder telemetryEnabled(boolean telemetryEnabled) { return this; } + /** + * Configure the telemetry sent to Auth0 on every request. Use this when building an SDK on top of + * auth0-java so that requests are attributed to the wrapping library, with auth0-java reported as the + * underlying library in the telemetry environment. + *

+ * If not set, telemetry defaults to identifying this library as {@code auth0-java}. + * + * @param name the name of the library sending the requests (e.g. the wrapping SDK's name). + * @param version the version of the library sending the requests. + * @return this builder instance. + */ + public Builder withTelemetry(String name, String version) { + this.telemetry = + new Telemetry(name, version, Telemetry.class.getPackage().getImplementationVersion()); + return this; + } + /** * Sets the maximum number of consecutive retries for API requests that fail due to rate-limits being reached. * By default, rate-limited requests will be retried a maximum of three times. To disable retries on rate-limit diff --git a/src/test/java/com/auth0/client/auth/AuthAPITest.java b/src/test/java/com/auth0/client/auth/AuthAPITest.java index d78699384..a0582708e 100644 --- a/src/test/java/com/auth0/client/auth/AuthAPITest.java +++ b/src/test/java/com/auth0/client/auth/AuthAPITest.java @@ -261,6 +261,44 @@ public void shouldCreateUserInfoRequest() throws Exception { assertThat(identities.get(0), hasEntry("isSocial", false)); } + // Telemetry + + @Test + public void shouldSendDefaultTelemetry() throws Exception { + Request request = api.userInfo("accessToken"); + server.jsonResponse(AUTH_USER_INFO, 200); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + String header = recordedRequest.getHeader("Auth0-Client"); + assertThat(header, is(notNullValue())); + com.fasterxml.jackson.databind.JsonNode telemetry = ObjectMapperProvider.getMapper() + .readTree(java.util.Base64.getUrlDecoder().decode(header)); + assertThat(telemetry.get("name").asText(), is("auth0-java")); + } + + @Test + public void shouldSendCustomTelemetryWhenConfigured() throws Exception { + AuthAPI customApi = AuthAPI.newBuilder(server.getBaseUrl(), CLIENT_ID, CLIENT_SECRET) + .withHttpClient(com.auth0.net.client.DefaultHttpClient.newBuilder() + .withTelemetry("my-wrapper-sdk", "1.2.3") + .build()) + .build(); + + Request request = customApi.userInfo("accessToken"); + server.jsonResponse(AUTH_USER_INFO, 200); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + String header = recordedRequest.getHeader("Auth0-Client"); + assertThat(header, is(notNullValue())); + com.fasterxml.jackson.databind.JsonNode telemetry = ObjectMapperProvider.getMapper() + .readTree(java.util.Base64.getUrlDecoder().decode(header)); + assertThat(telemetry.get("name").asText(), is("my-wrapper-sdk")); + assertThat(telemetry.get("version").asText(), is("1.2.3")); + assertThat(telemetry.get("env"), is(notNullValue())); + } + // Reset Password @Test diff --git a/src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java b/src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java new file mode 100644 index 000000000..ecab03957 --- /dev/null +++ b/src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java @@ -0,0 +1,53 @@ +package com.auth0.client.mgmt; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +import com.auth0.json.ObjectMapperProvider; +import com.fasterxml.jackson.databind.JsonNode; +import java.util.Base64; +import java.util.Map; +import org.junit.jupiter.api.Test; + +public class ManagementApiTelemetryTest { + + private JsonNode decodeTelemetry(ManagementApi api) throws Exception { + Map headers = api.clientOptions.headers(null); + String value = headers.get("Auth0-Client"); + assertThat(value, is(notNullValue())); + byte[] json = Base64.getUrlDecoder().decode(value); + return ObjectMapperProvider.getMapper().readTree(json); + } + + @Test + public void shouldSendDefaultTelemetryWhenNotConfigured() throws Exception { + ManagementApi api = ManagementApi.builder() + .domain("my-tenant.auth0.com") + .token("test-token") + .build(); + + JsonNode telemetry = decodeTelemetry(api); + assertThat(telemetry.get("name").asText(), is("auth0-java")); + } + + @Test + public void shouldSendCustomTelemetryWhenConfigured() throws Exception { + ManagementApi api = ManagementApi.builder() + .domain("my-tenant.auth0.com") + .token("test-token") + .withTelemetry("my-wrapper-sdk", "1.2.3") + .build(); + + JsonNode telemetry = decodeTelemetry(api); + assertThat(telemetry.get("name").asText(), is("my-wrapper-sdk")); + assertThat(telemetry.get("version").asText(), is("1.2.3")); + assertThat(telemetry.get("env"), is(notNullValue())); + } + + @Test + public void shouldReturnBuilderFromWithTelemetry() { + ManagementApiBuilder builder = ManagementApi.builder(); + ManagementApiBuilder result = builder.withTelemetry("my-wrapper-sdk", "1.2.3"); + assertThat(result, is(sameInstance(builder))); + } +} From 9fbd42ac80f83754f4fdc357a04a2064f931aa99 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Fri, 14 Aug 2026 18:01:50 +0530 Subject: [PATCH 2/4] fix spotless check and added test coverage --- .../client/mgmt/ManagementApiBuilder.java | 5 ++- .../auth0/net/client/DefaultHttpClient.java | 2 + .../com/auth0/client/auth/AuthAPITest.java | 43 +++++++++++++------ .../mgmt/ManagementApiTelemetryTest.java | 28 +++++++++++- 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/auth0/client/mgmt/ManagementApiBuilder.java b/src/main/java/com/auth0/client/mgmt/ManagementApiBuilder.java index 9e59bd75a..042621417 100644 --- a/src/main/java/com/auth0/client/mgmt/ManagementApiBuilder.java +++ b/src/main/java/com/auth0/client/mgmt/ManagementApiBuilder.java @@ -5,6 +5,7 @@ import com.auth0.client.mgmt.core.*; import com.auth0.net.Telemetry; +import com.auth0.utils.Asserts; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -203,7 +204,9 @@ public ManagementApiBuilder addHeader(String name, String value) { * @return This builder for method chaining */ public ManagementApiBuilder withTelemetry(String name, String version) { - this.telemetry = new Telemetry(name, version, Telemetry.class.getPackage().getImplementationVersion()); + Asserts.assertNotNull(name, "name"); + this.telemetry = + new Telemetry(name, version, Telemetry.class.getPackage().getImplementationVersion()); return this; } diff --git a/src/main/java/com/auth0/net/client/DefaultHttpClient.java b/src/main/java/com/auth0/net/client/DefaultHttpClient.java index af3422f91..7c86b457f 100644 --- a/src/main/java/com/auth0/net/client/DefaultHttpClient.java +++ b/src/main/java/com/auth0/net/client/DefaultHttpClient.java @@ -5,6 +5,7 @@ import com.auth0.net.RateLimitInterceptor; import com.auth0.net.Telemetry; import com.auth0.net.TelemetryInterceptor; +import com.auth0.utils.Asserts; import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -354,6 +355,7 @@ public Builder telemetryEnabled(boolean telemetryEnabled) { * @return this builder instance. */ public Builder withTelemetry(String name, String version) { + Asserts.assertNotNull(name, "name"); this.telemetry = new Telemetry(name, version, Telemetry.class.getPackage().getImplementationVersion()); return this; diff --git a/src/test/java/com/auth0/client/auth/AuthAPITest.java b/src/test/java/com/auth0/client/auth/AuthAPITest.java index a0582708e..5cfdd37b7 100644 --- a/src/test/java/com/auth0/client/auth/AuthAPITest.java +++ b/src/test/java/com/auth0/client/auth/AuthAPITest.java @@ -20,13 +20,16 @@ import com.auth0.net.BaseRequest; import com.auth0.net.Request; import com.auth0.net.SignUpRequest; +import com.auth0.net.Telemetry; import com.auth0.net.TokenRequest; import com.auth0.net.client.Auth0HttpClient; import com.auth0.net.client.Auth0HttpRequest; import com.auth0.net.client.Auth0HttpResponse; +import com.auth0.net.client.DefaultHttpClient; import com.auth0.net.client.HttpMethod; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.FileReader; import java.net.URLDecoder; @@ -263,24 +266,26 @@ public void shouldCreateUserInfoRequest() throws Exception { // Telemetry + private JsonNode decodeTelemetryHeader(RecordedRequest request) throws Exception { + String header = request.getHeader("Auth0-Client"); + assertThat(header, is(notNullValue())); + return ObjectMapperProvider.getMapper().readTree(Base64.getUrlDecoder().decode(header)); + } + @Test public void shouldSendDefaultTelemetry() throws Exception { Request request = api.userInfo("accessToken"); server.jsonResponse(AUTH_USER_INFO, 200); request.execute(); - RecordedRequest recordedRequest = server.takeRequest(); - String header = recordedRequest.getHeader("Auth0-Client"); - assertThat(header, is(notNullValue())); - com.fasterxml.jackson.databind.JsonNode telemetry = ObjectMapperProvider.getMapper() - .readTree(java.util.Base64.getUrlDecoder().decode(header)); + JsonNode telemetry = decodeTelemetryHeader(server.takeRequest()); assertThat(telemetry.get("name").asText(), is("auth0-java")); } @Test public void shouldSendCustomTelemetryWhenConfigured() throws Exception { AuthAPI customApi = AuthAPI.newBuilder(server.getBaseUrl(), CLIENT_ID, CLIENT_SECRET) - .withHttpClient(com.auth0.net.client.DefaultHttpClient.newBuilder() + .withHttpClient(DefaultHttpClient.newBuilder() .withTelemetry("my-wrapper-sdk", "1.2.3") .build()) .build(); @@ -288,15 +293,29 @@ public void shouldSendCustomTelemetryWhenConfigured() throws Exception { Request request = customApi.userInfo("accessToken"); server.jsonResponse(AUTH_USER_INFO, 200); request.execute(); - RecordedRequest recordedRequest = server.takeRequest(); - String header = recordedRequest.getHeader("Auth0-Client"); - assertThat(header, is(notNullValue())); - com.fasterxml.jackson.databind.JsonNode telemetry = ObjectMapperProvider.getMapper() - .readTree(java.util.Base64.getUrlDecoder().decode(header)); + JsonNode telemetry = decodeTelemetryHeader(server.takeRequest()); + assertThat(telemetry.get("name").asText(), is("my-wrapper-sdk")); + assertThat(telemetry.get("version").asText(), is("1.2.3")); + } + + @Test + public void shouldNestAuth0JavaInTelemetryEnv() throws Exception { + String value = new Telemetry("my-wrapper-sdk", "1.2.3", "auth0-java-9.9.9").getValue(); + + JsonNode telemetry = + ObjectMapperProvider.getMapper().readTree(Base64.getUrlDecoder().decode(value)); assertThat(telemetry.get("name").asText(), is("my-wrapper-sdk")); assertThat(telemetry.get("version").asText(), is("1.2.3")); - assertThat(telemetry.get("env"), is(notNullValue())); + assertThat(telemetry.get("env").get("auth0-java").asText(), is("auth0-java-9.9.9")); + } + + @Test + public void shouldThrowWhenTelemetryNameIsNull() { + verifyThrows( + IllegalArgumentException.class, + () -> DefaultHttpClient.newBuilder().withTelemetry(null, "1.2.3"), + "'name' cannot be null!"); } // Reset Password diff --git a/src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java b/src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java index ecab03957..04c9804c6 100644 --- a/src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java +++ b/src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java @@ -1,9 +1,12 @@ package com.auth0.client.mgmt; +import static com.auth0.AssertsUtil.verifyThrows; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +import com.auth0.client.mgmt.core.ClientOptions; import com.auth0.json.ObjectMapperProvider; +import com.auth0.net.Telemetry; import com.fasterxml.jackson.databind.JsonNode; import java.util.Base64; import java.util.Map; @@ -41,7 +44,22 @@ public void shouldSendCustomTelemetryWhenConfigured() throws Exception { JsonNode telemetry = decodeTelemetry(api); assertThat(telemetry.get("name").asText(), is("my-wrapper-sdk")); assertThat(telemetry.get("version").asText(), is("1.2.3")); - assertThat(telemetry.get("env"), is(notNullValue())); + } + + @Test + public void shouldNestAuth0JavaInTelemetryEnv() throws Exception { + ClientOptions options = ClientOptions.builder() + .environment(com.auth0.client.mgmt.core.Environment.DEFAULT) + .telemetry(new Telemetry("my-wrapper-sdk", "1.2.3", "auth0-java-9.9.9")) + .build(); + + String value = options.headers(null).get("Auth0-Client"); + assertThat(value, is(notNullValue())); + JsonNode telemetry = + ObjectMapperProvider.getMapper().readTree(Base64.getUrlDecoder().decode(value)); + assertThat(telemetry.get("name").asText(), is("my-wrapper-sdk")); + assertThat(telemetry.get("version").asText(), is("1.2.3")); + assertThat(telemetry.get("env").get("auth0-java").asText(), is("auth0-java-9.9.9")); } @Test @@ -50,4 +68,12 @@ public void shouldReturnBuilderFromWithTelemetry() { ManagementApiBuilder result = builder.withTelemetry("my-wrapper-sdk", "1.2.3"); assertThat(result, is(sameInstance(builder))); } + + @Test + public void shouldThrowWhenTelemetryNameIsNull() { + verifyThrows( + IllegalArgumentException.class, + () -> ManagementApi.builder().withTelemetry(null, "1.2.3"), + "'name' cannot be null!"); + } } From 8f43c5d13c1858318bb161c4085e6c95e1b0f128 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Mon, 17 Aug 2026 15:53:23 +0530 Subject: [PATCH 3/4] update java doc --- .../java/com/auth0/client/mgmt/core/ClientOptions.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java b/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java index f244ff7e6..e97e80827 100644 --- a/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java +++ b/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java @@ -178,9 +178,10 @@ public Builder addInterceptor(Interceptor interceptor) { } /** - * Configure the telemetry sent to Auth0 on every request. Used when building an SDK on top of - * auth0-java so requests are attributed to the wrapping library. If not set, telemetry defaults - * to identifying this library as {@code auth0-java}. + * Internal plumbing. Sets the pre-built {@link Telemetry} used for the {@code Auth0-Client} + * header. Prefer {@link com.auth0.client.mgmt.ManagementApiBuilder#withTelemetry(String, String)}, + * which constructs the telemetry with the correct auth0-java version. Passing a hand-built + * {@link Telemetry} here bypasses that and is not a supported way to identify a wrapping SDK. */ public Builder telemetry(Telemetry telemetry) { this.telemetry = telemetry; From cca7ccc8434bf4d0456886abd827d913c6708fca Mon Sep 17 00:00:00 2001 From: tanya732 Date: Wed, 19 Aug 2026 14:32:24 +0530 Subject: [PATCH 4/4] update clientOptions and add relevant tests --- .../auth0/client/mgmt/core/ClientOptions.java | 40 ++++++++++++++++++- .../mgmt/ManagementApiTelemetryTest.java | 22 ++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java b/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java index e97e80827..a8d1357a3 100644 --- a/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java +++ b/src/main/java/com/auth0/client/mgmt/core/ClientOptions.java @@ -27,6 +27,8 @@ public final class ClientOptions { private final int maxRetries; + private final Telemetry telemetry; + private ClientOptions( Environment environment, Map headers, @@ -49,6 +51,7 @@ private ClientOptions( this.httpClient = httpClient; this.timeout = timeout; this.maxRetries = maxRetries; + this.telemetry = telemetry; } public Environment environment() { @@ -94,6 +97,32 @@ public int maxRetries() { return this.maxRetries; } + /** + * The telemetry explicitly configured on this instance, or {@code null} if it was left to + * default to {@code auth0-java}. Package-private so {@link Builder#from(ClientOptions)} can + * carry it over; not part of the public API. + */ + Telemetry telemetry() { + return this.telemetry; + } + + /** + * The static headers configured on this instance, including the resolved {@code Auth0-Client} + * header. Package-private so {@link Builder#from(ClientOptions)} can carry them over; not part + * of the public API. + */ + Map headers() { + return this.headers; + } + + /** + * The dynamic header suppliers configured on this instance. Package-private so + * {@link Builder#from(ClientOptions)} can carry them over; not part of the public API. + */ + Map> headerSuppliers() { + return this.headerSuppliers; + } + public static Builder builder() { return new Builder(); } @@ -230,13 +259,22 @@ public ClientOptions build() { } /** - * Create a new Builder initialized with values from an existing ClientOptions + * Create a new Builder initialized with values from an existing ClientOptions. + * + *

Interceptors and logging are not copied explicitly: they are already baked into the + * {@link OkHttpClient} carried over here, and {@link #build()} preserves them via + * {@code newBuilder()}. Copying them would attach them a second time. The same applies to + * the retry interceptor, hence {@code maxRetries} is carried over for reporting only. */ public static Builder from(ClientOptions clientOptions) { Builder builder = new Builder(); builder.environment = clientOptions.environment(); builder.timeout = Optional.of(clientOptions.timeout(null)); builder.httpClient = clientOptions.httpClient(); + builder.maxRetries = clientOptions.maxRetries(); + builder.telemetry = clientOptions.telemetry(); + builder.headers.putAll(clientOptions.headers()); + builder.headerSuppliers.putAll(clientOptions.headerSuppliers()); return builder; } } diff --git a/src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java b/src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java index 04c9804c6..27b7a0b40 100644 --- a/src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java +++ b/src/test/java/com/auth0/client/mgmt/ManagementApiTelemetryTest.java @@ -62,6 +62,28 @@ public void shouldNestAuth0JavaInTelemetryEnv() throws Exception { assertThat(telemetry.get("env").get("auth0-java").asText(), is("auth0-java-9.9.9")); } + @Test + public void shouldPreserveTelemetryAndHeadersWhenCopyingOptions() throws Exception { + ClientOptions original = ClientOptions.builder() + .environment(com.auth0.client.mgmt.core.Environment.DEFAULT) + .telemetry(new Telemetry("my-wrapper-sdk", "1.2.3")) + .addHeader("Authorization", "Bearer test-token") + .addHeader("X-Dynamic", () -> "dynamic-value") + .maxRetries(5) + .build(); + + ClientOptions copy = ClientOptions.Builder.from(original).build(); + + Map headers = copy.headers(null); + JsonNode telemetry = + ObjectMapperProvider.getMapper().readTree(Base64.getUrlDecoder().decode(headers.get("Auth0-Client"))); + assertThat(telemetry.get("name").asText(), is("my-wrapper-sdk")); + assertThat(telemetry.get("version").asText(), is("1.2.3")); + assertThat(headers.get("Authorization"), is("Bearer test-token")); + assertThat(headers.get("X-Dynamic"), is("dynamic-value")); + assertThat(copy.maxRetries(), is(5)); + } + @Test public void shouldReturnBuilderFromWithTelemetry() { ManagementApiBuilder builder = ManagementApi.builder();