Skip to content

Commit 4fbff64

Browse files
committed
added changelog and a test
1 parent 1e064bb commit 4fbff64

File tree

2 files changed

+75
-13
lines changed

2 files changed

+75
-13
lines changed

NEXT_CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
refresh tokens by default (by adding the `offline_access` scope) in OAuth exchanges. This
99
option does not remove the scope from the user provided scopes if present.
1010

11+
* Fix 'external-browser' auth type to use the token if it is valid instead of forceful refresh everytime.
12+
1113
### Bug Fixes
1214

1315
### Documentation

databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/ExternalBrowserCredentialsProviderTest.java

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -246,45 +246,45 @@ void sessionCredentials() throws IOException {
246246
// Token caching tests
247247

248248
@Test
249-
void cacheWithValidTokenTest() throws IOException {
250-
// Create mock HTTP client (shouldn't be called for valid token)
249+
void cacheWithValidRefreshableTokenTest() throws IOException {
250+
// Create mock HTTP client (shouldn't be called for valid token).
251251
HttpClient mockHttpClient = Mockito.mock(HttpClient.class);
252252

253-
// Create a valid token with valid refresh token (expires in 1 hour - FRESH state)
253+
// Create a valid token with valid refresh token (expires in 1 hour - FRESH state).
254254
Instant futureTime = Instant.now().plusSeconds(3600);
255255
Token validToken = new Token("valid_access_token", "Bearer", "valid_refresh_token", futureTime);
256256

257-
// Create mock token cache that returns the valid token
257+
// Create mock token cache that returns the valid token.
258258
TokenCache mockTokenCache = Mockito.mock(TokenCache.class);
259259
Mockito.doReturn(validToken).when(mockTokenCache).load();
260260

261-
// Create config with HTTP client and mock token cache
261+
// Create config with HTTP client and mock token cache.
262262
DatabricksConfig config =
263263
new DatabricksConfig()
264264
.setAuthType("external-browser")
265265
.setHost("https://test.databricks.com")
266266
.setClientId("test-client-id")
267267
.setHttpClient(mockHttpClient);
268268

269-
// We need to provide OIDC endpoints
269+
// We need to provide OIDC endpoints.
270270
OpenIDConnectEndpoints endpoints =
271271
new OpenIDConnectEndpoints(
272272
"https://test.databricks.com/oidc/v1/token",
273273
"https://test.databricks.com/oidc/v1/authorize");
274274

275-
// Create our provider with the mock token cache
275+
// Create our provider with the mock token cache.
276276
ExternalBrowserCredentialsProvider provider =
277277
Mockito.spy(new ExternalBrowserCredentialsProvider(mockTokenCache));
278278

279-
// Spy on the config to inject the endpoints
279+
// Spy on the config to inject the endpoints.
280280
DatabricksConfig spyConfig = Mockito.spy(config);
281281
Mockito.doReturn(endpoints).when(spyConfig).getOidcEndpoints();
282282

283-
// Configure provider
283+
// Configure provider.
284284
HeaderFactory headerFactory = provider.configure(spyConfig);
285285
assertNotNull(headerFactory, "HeaderFactory should be created");
286286

287-
// Verify headers contain the CACHED valid token (no refresh needed!)
287+
// Verify headers contain the CACHED valid token (no refresh needed!).
288288
Map<String, String> headers = headerFactory.headers();
289289
assertEquals(
290290
"Bearer valid_access_token",
@@ -294,18 +294,78 @@ void cacheWithValidTokenTest() throws IOException {
294294
// Verify token was loaded from cache
295295
Mockito.verify(mockTokenCache, Mockito.times(1)).load();
296296

297-
// Verify NO HTTP call was made (token is still valid, no refresh needed)
297+
// Verify NO HTTP call was made (token is still valid, no refresh needed).
298298
Mockito.verify(mockHttpClient, Mockito.never()).execute(any(Request.class));
299299

300-
// Verify performBrowserAuth was NOT called since cached token is valid
300+
// Verify performBrowserAuth was NOT called since cached token is valid.
301301
Mockito.verify(provider, Mockito.never())
302302
.performBrowserAuth(
303303
any(DatabricksConfig.class),
304304
any(String.class),
305305
any(String.class),
306306
any(TokenCache.class));
307307

308-
// Verify token was NOT saved back to cache (we're using the cached one as-is)
308+
// Verify token was NOT saved back to cache (we're using the cached one as-is).
309+
Mockito.verify(mockTokenCache, Mockito.never()).save(any(Token.class));
310+
}
311+
312+
@Test
313+
void cacheWithValidNonRefreshableTokenTest() throws IOException {
314+
// Create mock HTTP client (shouldn't be called for valid token).
315+
HttpClient mockHttpClient = Mockito.mock(HttpClient.class);
316+
317+
// Create a valid token WITHOUT refresh token (expires in 1 hour - FRESH state).
318+
Instant futureTime = Instant.now().plusSeconds(3600);
319+
Token validTokenNoRefresh = new Token("valid_access_token", "Bearer", null, futureTime);
320+
321+
// Create mock token cache that returns the valid token.
322+
TokenCache mockTokenCache = Mockito.mock(TokenCache.class);
323+
Mockito.doReturn(validTokenNoRefresh).when(mockTokenCache).load();
324+
325+
// Create config with HTTP client and mock token cache.
326+
DatabricksConfig config =
327+
new DatabricksConfig()
328+
.setAuthType("external-browser")
329+
.setHost("https://test.databricks.com")
330+
.setClientId("test-client-id")
331+
.setHttpClient(mockHttpClient);
332+
333+
// We need to provide OIDC endpoints.
334+
OpenIDConnectEndpoints endpoints =
335+
new OpenIDConnectEndpoints(
336+
"https://test.databricks.com/oidc/v1/token",
337+
"https://test.databricks.com/oidc/v1/authorize");
338+
339+
// Create our provider with the mock token cache.
340+
ExternalBrowserCredentialsProvider provider =
341+
Mockito.spy(new ExternalBrowserCredentialsProvider(mockTokenCache));
342+
343+
// Spy on the config to inject the endpoints.
344+
DatabricksConfig spyConfig = Mockito.spy(config);
345+
Mockito.doReturn(endpoints).when(spyConfig).getOidcEndpoints();
346+
347+
// Configure provider.
348+
HeaderFactory headerFactory = provider.configure(spyConfig);
349+
assertNotNull(headerFactory, "HeaderFactory should be created");
350+
351+
// Verify headers contain the cached token (NOT browser auth!).
352+
Map<String, String> headers = headerFactory.headers();
353+
assertEquals(
354+
"Bearer valid_access_token",
355+
headers.get("Authorization"),
356+
"Should use cached valid token even without refresh token");
357+
358+
// Verify token was loaded from cache.
359+
Mockito.verify(mockTokenCache, Mockito.times(1)).load();
360+
361+
// Verify NO HTTP call was made (token is still valid, no refresh needed).
362+
Mockito.verify(mockHttpClient, Mockito.never()).execute(any(Request.class));
363+
364+
// Verify performBrowserAuth was NOT called.
365+
Mockito.verify(provider, Mockito.never())
366+
.performBrowserAuth(any(DatabricksConfig.class), any(), any(), any(TokenCache.class));
367+
368+
// Verify no token was saved (we're using the cached one as-is).
309369
Mockito.verify(mockTokenCache, Mockito.never()).save(any(Token.class));
310370
}
311371

0 commit comments

Comments
 (0)