@@ -90,6 +90,16 @@ export type DatabricksDriverConfiguration = JDBCDriverConfiguration &
9090 */
9191 token ?: string ,
9292
93+ /**
94+ * Databricks OAuth Client ID.
95+ */
96+ oauthClientId ?: string ,
97+
98+ /**
99+ * Databricks OAuth Client Secret.
100+ */
101+ oauthClientSecret ?: string ,
102+
93103 /**
94104 * Azure tenant Id
95105 */
@@ -200,6 +210,41 @@ export class DatabricksDriver extends JDBCDriver {
200210 }
201211
202212 const [ uid , pwd , cleanedUrl ] = extractAndRemoveUidPwdFromJdbcUrl ( url ) ;
213+ const passwd = conf ?. token ||
214+ getEnv ( 'databricksToken' , { dataSource } ) ||
215+ pwd ;
216+ const oauthClientId = conf ?. oauthClientId || getEnv ( 'databricksOAuthClientId' , { dataSource } ) ;
217+ const oauthClientSecret = conf ?. oauthClientSecret || getEnv ( 'databricksOAuthClientSecret' , { dataSource } ) ;
218+
219+ if ( oauthClientId && ! oauthClientSecret ) {
220+ throw new Error ( 'Invalid credentials: No OAuth Client Secret provided' ) ;
221+ } else if ( ! oauthClientId && oauthClientSecret ) {
222+ throw new Error ( 'Invalid credentials: No OAuth Client ID provided' ) ;
223+ } else if ( ! oauthClientId && ! oauthClientSecret && ! passwd ) {
224+ throw new Error ( 'No credentials provided' ) ;
225+ }
226+
227+ const user = uid || 'token' ;
228+
229+ let authProps = { } ;
230+
231+ // OAuth has an advantage over UID+PWD
232+ // For magic numbers below - see Databricks docs:
233+ // https://docs.databricks.com/aws/en/integrations/jdbc-oss/configure#authenticate-the-driver
234+ if ( oauthClientId ) {
235+ authProps = {
236+ OAuth2ClientID : oauthClientId ,
237+ OAuth2Secret : oauthClientSecret ,
238+ AuthMech : 11 ,
239+ Auth_Flow : 1 ,
240+ } ;
241+ } else {
242+ authProps = {
243+ UID : user ,
244+ PWD : passwd ,
245+ AuthMech : 3 ,
246+ } ;
247+ }
203248
204249 const config : DatabricksDriverConfiguration = {
205250 ...conf ,
@@ -208,11 +253,7 @@ export class DatabricksDriver extends JDBCDriver {
208253 drivername : 'com.databricks.client.jdbc.Driver' ,
209254 customClassPath : undefined ,
210255 properties : {
211- UID : uid ,
212- PWD :
213- conf ?. token ||
214- getEnv ( 'databricksToken' , { dataSource } ) ||
215- pwd ,
256+ ...authProps ,
216257 UserAgentEntry : 'CubeDev_Cube' ,
217258 } ,
218259 catalog :
@@ -292,7 +333,31 @@ export class DatabricksDriver extends JDBCDriver {
292333 }
293334
294335 public override async testConnection ( ) {
295- const token = `Bearer ${ this . config . properties . PWD } ` ;
336+ let token : string ;
337+
338+ // Databricks docs on accessing REST API
339+ // https://docs.databricks.com/aws/en/dev-tools/auth/oauth-m2m
340+ if ( this . config . properties . OAuth2Secret ) {
341+ // Need to exchange client ID + Secret => Access token
342+
343+ const basicAuth = Buffer . from ( `${ this . config . properties . OAuth2ClientID } :${ this . config . properties . OAuth2Secret } ` ) . toString ( 'base64' ) ;
344+
345+ const res = await fetch ( `https://${ this . parsedConnectionProperties . host } /oidc/v1/token` , {
346+ method : 'POST' ,
347+ headers : {
348+ Authorization : `Basic ${ basicAuth } ` ,
349+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
350+ } ,
351+ body : new URLSearchParams ( {
352+ grant_type : 'client_credentials' ,
353+ scope : 'all-apis' ,
354+ } ) ,
355+ } ) ;
356+ const resp = await res . json ( ) ;
357+ token = resp . access_token ;
358+ } else {
359+ token = `Bearer ${ this . config . properties . PWD } ` ;
360+ }
296361
297362 const res = await fetch ( `https://${ this . parsedConnectionProperties . host } /api/2.0/sql/warehouses/${ this . parsedConnectionProperties . warehouseId } ` , {
298363 headers : { Authorization : token } ,
0 commit comments