@@ -162,6 +162,10 @@ export class DatabricksDriver extends JDBCDriver {
162162
163163 private readonly parsedConnectionProperties : ParsedConnectionProperties ;
164164
165+ private accessToken : string | undefined ;
166+
167+ private accessTokenExpires : number = 0 ;
168+
165169 public static dialectClass ( ) {
166170 return DatabricksQuery ;
167171 }
@@ -332,29 +336,52 @@ export class DatabricksDriver extends JDBCDriver {
332336 this . showDeprecations ( ) ;
333337 }
334338
339+ private async fetchAccessToken ( ) : Promise < void > {
340+ // Need to exchange client ID + Secret => Access token
341+
342+ const basicAuth = Buffer . from ( `${ this . config . properties . OAuth2ClientID } :${ this . config . properties . OAuth2Secret } ` ) . toString ( 'base64' ) ;
343+
344+ const res = await fetch ( `https://${ this . parsedConnectionProperties . host } /oidc/v1/token` , {
345+ method : 'POST' ,
346+ headers : {
347+ Authorization : `Basic ${ basicAuth } ` ,
348+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
349+ } ,
350+ body : new URLSearchParams ( {
351+ grant_type : 'client_credentials' ,
352+ scope : 'all-apis' ,
353+ } ) ,
354+ } ) ;
355+
356+ if ( ! res . ok ) {
357+ throw new Error ( `Failed to get access token: ${ res . statusText } ` ) ;
358+ }
359+
360+ const resp = await res . json ( ) ;
361+
362+ this . accessToken = resp . access_token ;
363+ this . accessTokenExpires = Date . now ( ) + resp . expires_in * 1000 - 60_000 ;
364+ }
365+
366+ private async getValidAccessToken ( ) : Promise < string > {
367+ if (
368+ ! this . accessToken ||
369+ ! this . accessTokenExpires ||
370+ Date . now ( ) >= this . accessTokenExpires
371+ ) {
372+ await this . fetchAccessToken ( ) ;
373+ }
374+ return this . accessToken ! ;
375+ }
376+
335377 public override async testConnection ( ) {
336378 let token : string ;
337379
338380 // Databricks docs on accessing REST API
339381 // https://docs.databricks.com/aws/en/dev-tools/auth/oauth-m2m
340382 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 ;
383+ const at = await this . getValidAccessToken ( ) ;
384+ token = `Bearer ${ at } ` ;
358385 } else {
359386 token = `Bearer ${ this . config . properties . PWD } ` ;
360387 }
0 commit comments