diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/AzureCliCredentialsProvider.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/AzureCliCredentialsProvider.java index 1c97a7ac9..77f9c9fdb 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/AzureCliCredentialsProvider.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/AzureCliCredentialsProvider.java @@ -99,7 +99,8 @@ public OAuthHeaderFactory configure(DatabricksConfig config) { () -> { Token token = tokenSource.getToken(); Map headers = new HashMap<>(); - headers.put("Authorization", token.getTokenType() + " " + token.getAccessToken()); + headers.put( + "Authorization", token.getCanonicalTokenType() + " " + token.getAccessToken()); if (finalMgmtTokenSource != null) { AzureUtils.addSpManagementToken(finalMgmtTokenSource, headers); } diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthHeaderFactory.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthHeaderFactory.java index 614614c55..94580ff12 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthHeaderFactory.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthHeaderFactory.java @@ -51,7 +51,8 @@ public Token getToken() { public Map headers() { Token token = tokenSource.getToken(); Map headers = new HashMap<>(); - headers.put("Authorization", token.getTokenType() + " " + token.getAccessToken()); + headers.put( + "Authorization", token.getCanonicalTokenType() + " " + token.getAccessToken()); return headers; } }; diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/Token.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/Token.java index 4a3b42a7e..cafc66587 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/Token.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/Token.java @@ -51,6 +51,22 @@ public String getTokenType() { return tokenType; } + /** + * Returns the token type canonicalized for use as the Authorization header scheme. Per RFC 6749 + * §5.1 / RFC 6750 §2.1, identity providers may return {@code token_type} in any case (e.g. + * "bearer", "BEARER"). Some downstream servers and proxies reject anything other than the + * canonical "Bearer" capitalization, so we normalize that scheme here. Other schemes are returned + * unchanged. + * + * @return the canonicalized token type + */ + public String getCanonicalTokenType() { + if ("bearer".equalsIgnoreCase(tokenType)) { + return "Bearer"; + } + return tokenType; + } + /** * Returns the refresh token, if available. May be null for non-refreshable tokens. * diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/service/serving/ServingEndpointsDataPlaneImpl.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/service/serving/ServingEndpointsDataPlaneImpl.java index 5410d88d7..9c4806440 100755 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/service/serving/ServingEndpointsDataPlaneImpl.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/service/serving/ServingEndpointsDataPlaneImpl.java @@ -68,7 +68,7 @@ public QueryEndpointResponse query(QueryEndpointInput request) { } RequestOptions options = new RequestOptions() - .withAuthorization(token.getTokenType() + " " + token.getAccessToken()) + .withAuthorization(token.getCanonicalTokenType() + " " + token.getAccessToken()) .withUrl(path); return apiClient.execute(req, QueryEndpointResponse.class, options); diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthHeaderFactoryTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthHeaderFactoryTest.java index f0b83153c..41b936e79 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthHeaderFactoryTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthHeaderFactoryTest.java @@ -36,7 +36,19 @@ private static Stream provideTokenSourceTestCases() { Arguments.of( "Token with custom type", new Token(TOKEN_VALUE, "Custom", expiry), - Collections.singletonMap("Authorization", "Custom " + TOKEN_VALUE))); + Collections.singletonMap("Authorization", "Custom " + TOKEN_VALUE)), + Arguments.of( + "Lowercase bearer is canonicalized", + new Token(TOKEN_VALUE, "bearer", expiry), + Collections.singletonMap("Authorization", "Bearer " + TOKEN_VALUE)), + Arguments.of( + "Uppercase BEARER is canonicalized", + new Token(TOKEN_VALUE, "BEARER", expiry), + Collections.singletonMap("Authorization", "Bearer " + TOKEN_VALUE)), + Arguments.of( + "Mixed-case BeArEr is canonicalized", + new Token(TOKEN_VALUE, "BeArEr", expiry), + Collections.singletonMap("Authorization", "Bearer " + TOKEN_VALUE))); } @ParameterizedTest(name = "{0}") diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/TokenTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/TokenTest.java index a0173cbf8..454e7bbda 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/TokenTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/TokenTest.java @@ -29,4 +29,20 @@ void createRefreshableToken() { assertEquals(refreshToken, token.getRefreshToken()); assertEquals(currentInstant.plusSeconds(300), token.getExpiry()); } + + @Test + void canonicalTokenTypeNormalizesBearerCasing() { + Instant expiry = currentInstant.plusSeconds(300); + assertEquals("Bearer", new Token(accessToken, "Bearer", expiry).getCanonicalTokenType()); + assertEquals("Bearer", new Token(accessToken, "bearer", expiry).getCanonicalTokenType()); + assertEquals("Bearer", new Token(accessToken, "BEARER", expiry).getCanonicalTokenType()); + assertEquals("Bearer", new Token(accessToken, "BeArEr", expiry).getCanonicalTokenType()); + } + + @Test + void canonicalTokenTypePreservesNonBearerSchemes() { + Instant expiry = currentInstant.plusSeconds(300); + assertEquals("Custom", new Token(accessToken, "Custom", expiry).getCanonicalTokenType()); + assertEquals("MAC", new Token(accessToken, "MAC", expiry).getCanonicalTokenType()); + } }