@@ -6,17 +6,22 @@ interface AuthenticatorResult {
66 refreshToken : string ;
77}
88
9+ interface OidcCredentials {
10+ silentRefresh : boolean ;
11+ }
12+
913export interface OidcAuthFlow {
1014 refresh : ( ) => Promise < AuthenticatorResult > ;
1115}
1216
1317export class OidcAuthenticator {
1418 private readonly http : HttpClient ;
15- private readonly creds : any ;
19+ private readonly creds : OidcCredentials ;
1620 private accessToken : string ;
1721 private refreshToken ?: string ;
1822 private expiresAt : number ;
1923 private refreshRunning : boolean ;
24+ private refreshInterval ! : NodeJS . Timeout ;
2025
2126 constructor ( http : HttpClient , creds : any ) {
2227 this . http = http ;
@@ -57,10 +62,7 @@ export class OidcAuthenticator {
5762 this . accessToken = resp . accessToken ;
5863 this . expiresAt = resp . expiresAt ;
5964 this . refreshToken = resp . refreshToken ;
60- if ( ! this . refreshRunning && this . refreshTokenProvided ( ) ) {
61- this . runBackgroundTokenRefresh ( authenticator ) ;
62- this . refreshRunning = true ;
63- }
65+ this . startTokenRefresh ( authenticator ) ;
6466 } ) ;
6567 } ;
6668
@@ -75,17 +77,25 @@ export class OidcAuthenticator {
7577 } ) ;
7678 } ;
7779
78- runBackgroundTokenRefresh = ( authenticator : { refresh : ( ) => any } ) => {
79- setInterval ( async ( ) => {
80- // check every 30s if the token will expire in <= 1m,
81- // if so, refresh
82- if ( this . expiresAt - Date . now ( ) <= 60_000 ) {
83- const resp = await authenticator . refresh ( ) ;
84- this . accessToken = resp . accessToken ;
85- this . expiresAt = resp . expiresAt ;
86- this . refreshToken = resp . refreshToken ;
87- }
88- } , 30_000 ) ;
80+ startTokenRefresh = ( authenticator : { refresh : ( ) => any } ) => {
81+ if ( this . creds . silentRefresh && ! this . refreshRunning && this . refreshTokenProvided ( ) ) {
82+ this . refreshInterval = setInterval ( async ( ) => {
83+ // check every 30s if the token will expire in <= 1m,
84+ // if so, refresh
85+ if ( this . expiresAt - Date . now ( ) <= 60_000 ) {
86+ const resp = await authenticator . refresh ( ) ;
87+ this . accessToken = resp . accessToken ;
88+ this . expiresAt = resp . expiresAt ;
89+ this . refreshToken = resp . refreshToken ;
90+ }
91+ } , 30_000 ) ;
92+ this . refreshRunning = true ;
93+ }
94+ } ;
95+
96+ stopTokenRefresh = ( ) => {
97+ clearInterval ( this . refreshInterval ) ;
98+ this . refreshRunning = false ;
8999 } ;
90100
91101 refreshTokenProvided = ( ) => {
@@ -109,16 +119,19 @@ export interface UserPasswordCredentialsInput {
109119 username : string ;
110120 password ?: string ;
111121 scopes ?: any [ ] ;
122+ silentRefresh ?: boolean ;
112123}
113124
114- export class AuthUserPasswordCredentials {
125+ export class AuthUserPasswordCredentials implements OidcCredentials {
115126 private username : string ;
116127 private password ?: string ;
117128 private scopes ?: any [ ] ;
129+ public readonly silentRefresh : boolean ;
118130 constructor ( creds : UserPasswordCredentialsInput ) {
119131 this . username = creds . username ;
120132 this . password = creds . password ;
121133 this . scopes = creds . scopes ;
134+ this . silentRefresh = parseSilentRefresh ( creds . silentRefresh ) ;
122135 }
123136}
124137
@@ -190,18 +203,21 @@ export interface AccessTokenCredentialsInput {
190203 accessToken : string ;
191204 expiresIn : number ;
192205 refreshToken ?: string ;
206+ silentRefresh ?: boolean ;
193207}
194208
195- export class AuthAccessTokenCredentials {
209+ export class AuthAccessTokenCredentials implements OidcCredentials {
196210 public readonly accessToken : string ;
197211 public readonly expiresAt : number ;
198212 public readonly refreshToken ?: string ;
213+ public readonly silentRefresh : boolean ;
199214
200215 constructor ( creds : AccessTokenCredentialsInput ) {
201216 this . validate ( creds ) ;
202217 this . accessToken = creds . accessToken ;
203218 this . expiresAt = calcExpirationEpoch ( creds . expiresIn ) ;
204219 this . refreshToken = creds . refreshToken ;
220+ this . silentRefresh = parseSilentRefresh ( creds . silentRefresh ) ;
205221 }
206222
207223 validate = ( creds : AccessTokenCredentialsInput ) => {
@@ -270,15 +286,18 @@ class AccessTokenAuthenticator implements OidcAuthFlow {
270286export interface ClientCredentialsInput {
271287 clientSecret : string ;
272288 scopes ?: any [ ] ;
289+ silentRefresh ?: boolean ;
273290}
274291
275- export class AuthClientCredentials {
292+ export class AuthClientCredentials implements OidcCredentials {
276293 private clientSecret : any ;
277294 private scopes ?: any [ ] ;
295+ public readonly silentRefresh : boolean ;
278296
279297 constructor ( creds : ClientCredentialsInput ) {
280298 this . clientSecret = creds . clientSecret ;
281299 this . scopes = creds . scopes ;
300+ this . silentRefresh = parseSilentRefresh ( creds . silentRefresh ) ;
282301 }
283302}
284303
@@ -345,3 +364,12 @@ export class ApiKey {
345364function calcExpirationEpoch ( expiresIn : number ) : number {
346365 return Date . now ( ) + ( expiresIn - 2 ) * 1000 ; // -2 for some lag
347366}
367+
368+ function parseSilentRefresh ( silentRefresh : boolean | undefined ) : boolean {
369+ // Silent token refresh by default
370+ if ( silentRefresh === undefined ) {
371+ return true ;
372+ } else {
373+ return silentRefresh ;
374+ }
375+ }
0 commit comments