From d67a4e8cff79cddbda9cd56cb4f8fd7146c75351 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Mon, 30 Mar 2026 11:12:32 +0530 Subject: [PATCH] Added telemetry Support --- auth0-api-java/build.gradle | 6 ++ .../auth0/telemetry/TelemetryProvider.java | 64 +++++++++++++++++++ .../com/auth0/validators/JWTValidator.java | 30 ++++++++- .../resources/auth0-client-info.properties | 2 + .../telemetry/TelemetryProviderTest.java | 39 +++++++++++ 5 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 auth0-api-java/src/main/java/com/auth0/telemetry/TelemetryProvider.java create mode 100644 auth0-api-java/src/main/resources/auth0-client-info.properties create mode 100644 auth0-api-java/src/test/java/com/auth0/telemetry/TelemetryProviderTest.java diff --git a/auth0-api-java/build.gradle b/auth0-api-java/build.gradle index 419080f..35206c3 100644 --- a/auth0-api-java/build.gradle +++ b/auth0-api-java/build.gradle @@ -44,6 +44,12 @@ repositories { mavenCentral() } +processResources { + filesMatching('auth0-client-info.properties') { + expand(version: project.version) + } +} + test { useJUnit() testLogging { diff --git a/auth0-api-java/src/main/java/com/auth0/telemetry/TelemetryProvider.java b/auth0-api-java/src/main/java/com/auth0/telemetry/TelemetryProvider.java new file mode 100644 index 0000000..4ef9718 --- /dev/null +++ b/auth0-api-java/src/main/java/com/auth0/telemetry/TelemetryProvider.java @@ -0,0 +1,64 @@ +package com.auth0.telemetry; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Properties; + +/** + * Provides the Base64-encoded Auth0-Client telemetry header value. + * + * The payload is a JSON object: {"name":"springboot-api","version":"x.y.z","java":"17"} + */ +public final class TelemetryProvider { + + private static final String PROPERTIES_FILE = "auth0-client-info.properties"; + private static final String UNKNOWN = "unknown"; + + private static volatile String cachedHeaderValue; + + private TelemetryProvider() { + } + + /** + * Returns the Base64url-encoded telemetry header value. + * + * @return the Auth0-Client header value, or null if it cannot be built + */ + public static String getHeaderValue() { + if (cachedHeaderValue != null) { + return cachedHeaderValue; + } + synchronized (TelemetryProvider.class) { + if (cachedHeaderValue != null) { + return cachedHeaderValue; + } + cachedHeaderValue = buildHeaderValue(); + return cachedHeaderValue; + } + } + + private static String buildHeaderValue() { + String name = UNKNOWN; + String version = UNKNOWN; + + try (InputStream is = TelemetryProvider.class.getClassLoader() + .getResourceAsStream(PROPERTIES_FILE)) { + if (is != null) { + Properties props = new Properties(); + props.load(is); + name = props.getProperty("name", UNKNOWN); + version = props.getProperty("version", UNKNOWN); + } + } catch (IOException ignored) { + // Fall through with defaults + } + + String javaVersion = System.getProperty("java.version", UNKNOWN); + + String json = "{\"name\":\"" + name + "\",\"version\":\"" + version + "\",\"java\":\"" + javaVersion + "\"}"; + + return java.util.Base64.getUrlEncoder().withoutPadding() + .encodeToString(json.getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/auth0-api-java/src/main/java/com/auth0/validators/JWTValidator.java b/auth0-api-java/src/main/java/com/auth0/validators/JWTValidator.java index 9d655dc..442a1b6 100644 --- a/auth0-api-java/src/main/java/com/auth0/validators/JWTValidator.java +++ b/auth0-api-java/src/main/java/com/auth0/validators/JWTValidator.java @@ -12,8 +12,14 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.models.HttpRequestInfo; +import com.auth0.telemetry.TelemetryProvider; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; import java.security.interfaces.RSAPublicKey; +import java.util.HashMap; import java.util.Map; import static com.auth0.jwt.JWT.require; @@ -41,7 +47,7 @@ public JWTValidator(AuthOptions authOptions) { } this.authOptions = authOptions; - this.jwkProvider = new UrlJwkProvider(authOptions.getDomain()); + this.jwkProvider = createJwkProvider(authOptions.getDomain()); } /** @@ -170,6 +176,28 @@ private BaseAuthException wrapAsValidationException(Exception e) { return new VerifyAccessTokenException("JWT claim validation failed"); } + private static JwkProvider createJwkProvider(String domain) { + Map headers = new HashMap<>(); + headers.put("Accept", "application/json"); + + String telemetry = TelemetryProvider.getHeaderValue(); + if (telemetry != null) { + headers.put("Auth0-Client", telemetry); + } + + String normalizedDomain = domain; + if (!normalizedDomain.startsWith("http")) { + normalizedDomain = "https://" + normalizedDomain; + } + try { + URI uri = new URI(normalizedDomain + "/.well-known/jwks.json").normalize(); + URL url = uri.toURL(); + return new UrlJwkProvider(url, null, null, null, headers); + } catch (URISyntaxException | MalformedURLException e) { + throw new IllegalArgumentException("Invalid domain: " + domain, e); + } + } + public AuthOptions getAuthOptions() { return authOptions; } diff --git a/auth0-api-java/src/main/resources/auth0-client-info.properties b/auth0-api-java/src/main/resources/auth0-client-info.properties new file mode 100644 index 0000000..0081a9f --- /dev/null +++ b/auth0-api-java/src/main/resources/auth0-client-info.properties @@ -0,0 +1,2 @@ +version=${version} +name=springboot-api diff --git a/auth0-api-java/src/test/java/com/auth0/telemetry/TelemetryProviderTest.java b/auth0-api-java/src/test/java/com/auth0/telemetry/TelemetryProviderTest.java new file mode 100644 index 0000000..d726e86 --- /dev/null +++ b/auth0-api-java/src/test/java/com/auth0/telemetry/TelemetryProviderTest.java @@ -0,0 +1,39 @@ +package com.auth0.telemetry; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TelemetryProviderTest { + + @Test + @SuppressWarnings("unchecked") + public void getHeaderValue_returnsValidBase64Json() throws Exception { + String headerValue = TelemetryProvider.getHeaderValue(); + assertThat(headerValue).isNotNull().isNotEmpty(); + + byte[] decoded = Base64.getUrlDecoder().decode(headerValue); + String json = new String(decoded, StandardCharsets.UTF_8); + + ObjectMapper mapper = new ObjectMapper(); + Map payload = mapper.readValue(json, Map.class); + + assertThat(payload).containsKey("name"); + assertThat(payload).containsKey("version"); + assertThat(payload).containsKey("java"); + assertThat(payload.get("name")).isEqualTo("springboot-api"); + assertThat(payload.get("java")).isEqualTo(System.getProperty("java.version")); + } + + @Test + public void getHeaderValue_isCached() { + String first = TelemetryProvider.getHeaderValue(); + String second = TelemetryProvider.getHeaderValue(); + assertThat(first).isSameAs(second); + } +}