55import com .databricks .sdk .core .DatabricksException ;
66import com .databricks .sdk .core .HeaderFactory ;
77import java .io .IOException ;
8+ import java .nio .file .Path ;
89import org .slf4j .Logger ;
910import org .slf4j .LoggerFactory ;
1011
1112/**
1213 * A {@code CredentialsProvider} which implements the Authorization Code + PKCE flow by opening a
13- * browser for the user to authorize the application. Uses the cache from {@link
14- * DatabricksConfig#getTokenCache()}, tokens will be cached to avoid repeated authentication .
14+ * browser for the user to authorize the application. Uses a specified TokenCache or creates a
15+ * default one if none is provided .
1516 */
1617public class ExternalBrowserCredentialsProvider implements CredentialsProvider {
1718 private static final Logger LOGGER =
1819 LoggerFactory .getLogger (ExternalBrowserCredentialsProvider .class );
1920
21+ private TokenCache tokenCache ;
22+
23+ /**
24+ * Creates a new ExternalBrowserCredentialsProvider with the specified TokenCache.
25+ *
26+ * @param tokenCache the TokenCache to use for caching tokens
27+ */
28+ public ExternalBrowserCredentialsProvider (TokenCache tokenCache ) {
29+ this .tokenCache = tokenCache ;
30+ }
31+
32+ /**
33+ * Creates a new ExternalBrowserCredentialsProvider with a default TokenCache. A FileTokenCache
34+ * will be created when credentials are configured.
35+ */
36+ public ExternalBrowserCredentialsProvider () {
37+ this (null );
38+ }
39+
2040 @ Override
2141 public String authType () {
2242 return "external-browser" ;
2343 }
2444
2545 @ Override
2646 public HeaderFactory configure (DatabricksConfig config ) {
27- if (config .getHost () == null
28- || config .getClientId () == null
29- || !config .getAuthType ().equals ("external-browser" )) {
47+ if (config .getHost () == null || config .getAuthType () != "external-browser" ) {
3048 return null ;
3149 }
32-
3350 try {
34- // Get the token cache from config
35- TokenCache tokenCache = config .getTokenCache ();
51+ if (tokenCache == null ) {
52+ // Create a default FileTokenCache based on config
53+ Path cachePath =
54+ TokenCacheUtils .getCacheFilePath (
55+ config .getHost (), config .getClientId (), config .getScopes ());
56+ tokenCache = new FileTokenCache (cachePath );
57+ }
3658
3759 // First try to use the cached token if available (will return null if disabled)
3860 Token cachedToken = tokenCache .load ();
@@ -49,11 +71,11 @@ public HeaderFactory configure(DatabricksConfig config) {
4971 .withClientSecret (config .getClientSecret ())
5072 .withTokenUrl (config .getOidcEndpoints ().getTokenEndpoint ())
5173 .withRedirectUrl (config .getEffectiveOAuthRedirectUrl ())
74+ .withTokenCache (tokenCache )
5275 .build ();
5376
5477 LOGGER .debug ("Using cached token, will immediately refresh" );
5578 cachedCreds .token = cachedCreds .refresh ();
56- tokenCache .save (cachedCreds .getToken ());
5779 return cachedCreds .configure (config );
5880 } catch (Exception e ) {
5981 // If token refresh fails, log and continue to browser auth
@@ -62,7 +84,7 @@ public HeaderFactory configure(DatabricksConfig config) {
6284 }
6385
6486 // If no cached token or refresh failed, perform browser auth
65- SessionCredentials credentials = performBrowserAuth (config );
87+ SessionCredentials credentials = performBrowserAuth (config , tokenCache );
6688 tokenCache .save (credentials .getToken ());
6789 return credentials .configure (config );
6890 } catch (IOException | DatabricksException e ) {
@@ -71,10 +93,24 @@ public HeaderFactory configure(DatabricksConfig config) {
7193 }
7294 }
7395
74- SessionCredentials performBrowserAuth (DatabricksConfig config ) throws IOException {
96+ SessionCredentials performBrowserAuth (DatabricksConfig config , TokenCache tokenCache )
97+ throws IOException {
7598 LOGGER .debug ("Performing browser authentication" );
7699 OAuthClient client = new OAuthClient (config );
77100 Consent consent = client .initiateConsent ();
78- return consent .launchExternalBrowser ();
101+
102+ // Use the existing browser flow to get credentials
103+ SessionCredentials credentials = consent .launchExternalBrowser ();
104+
105+ // Create a new SessionCredentials with the same token but with our token cache
106+ return new SessionCredentials .Builder ()
107+ .withToken (credentials .getToken ())
108+ .withHttpClient (config .getHttpClient ())
109+ .withClientId (config .getClientId ())
110+ .withClientSecret (config .getClientSecret ())
111+ .withTokenUrl (config .getOidcEndpoints ().getTokenEndpoint ())
112+ .withRedirectUrl (config .getEffectiveOAuthRedirectUrl ())
113+ .withTokenCache (tokenCache )
114+ .build ();
79115 }
80116}
0 commit comments