@@ -139,7 +139,7 @@ export class Auth implements AuthService, ConnectionManager {
139
139
private readonly store : ProfileStore ,
140
140
private readonly iamProfileProvider = CredentialsProviderManager . getInstance ( ) ,
141
141
private readonly createSsoClient = SsoClient . create . bind ( SsoClient ) ,
142
- private readonly createTokenProvider = createFactoryFunction ( SsoAccessTokenProvider )
142
+ private readonly createSsoTokenProvider = createFactoryFunction ( SsoAccessTokenProvider )
143
143
) { }
144
144
145
145
#activeConnection: Mutable < StatefulConnection > | undefined
@@ -169,7 +169,7 @@ export class Auth implements AuthService, ConnectionManager {
169
169
public async reauthenticate ( { id } : Pick < Connection , 'id' > ) : Promise < Connection > {
170
170
const profile = this . store . getProfileOrThrow ( id )
171
171
if ( profile . type === 'sso' ) {
172
- const provider = this . getTokenProvider ( id , profile )
172
+ const provider = this . getSsoTokenProvider ( id , profile )
173
173
await this . authenticate ( id , ( ) => provider . createToken ( ) )
174
174
175
175
return this . getSsoConnection ( id , profile )
@@ -184,14 +184,13 @@ export class Auth implements AuthService, ConnectionManager {
184
184
public async useConnection ( { id } : Pick < SsoConnection , 'id' > ) : Promise < SsoConnection >
185
185
public async useConnection ( { id } : Pick < IamConnection , 'id' > ) : Promise < IamConnection >
186
186
public async useConnection ( { id } : Pick < Connection , 'id' > ) : Promise < Connection > {
187
+ await this . refreshConnectionState ( { id } )
188
+
187
189
const profile = this . store . getProfile ( id )
188
190
if ( profile === undefined ) {
189
191
throw new Error ( `Connection does not exist: ${ id } ` )
190
192
}
191
- getLogger ( ) . info ( `auth: validating connection before using it: ${ id } ` )
192
- const validated = await this . validateConnection ( id , profile )
193
- const conn =
194
- validated . type === 'sso' ? this . getSsoConnection ( id , validated ) : this . getIamConnection ( id , validated )
193
+ const conn = profile . type === 'sso' ? this . getSsoConnection ( id , profile ) : this . getIamConnection ( id , profile )
195
194
196
195
this . #activeConnection = conn
197
196
this . #onDidChangeActiveConnection. fire ( conn )
@@ -253,7 +252,7 @@ export class Auth implements AuthService, ConnectionManager {
253
252
this . store ,
254
253
id ,
255
254
profile ,
256
- this . createSsoClient ( profile . ssoRegion , this . getTokenProvider ( id , profile ) )
255
+ this . createSsoClient ( profile . ssoRegion , this . getSsoTokenProvider ( id , profile ) )
257
256
)
258
257
)
259
258
. catch ( err => {
@@ -276,7 +275,7 @@ export class Auth implements AuthService, ConnectionManager {
276
275
}
277
276
278
277
const id = uuid . v4 ( )
279
- const tokenProvider = this . getTokenProvider ( id , {
278
+ const tokenProvider = this . getSsoTokenProvider ( id , {
280
279
...profile ,
281
280
metadata : { connectionState : 'unauthenticated' } ,
282
281
} )
@@ -344,10 +343,10 @@ export class Auth implements AuthService, ConnectionManager {
344
343
if ( profile . type === 'iam' ) {
345
344
throw new ToolkitError ( 'Auth: Cannot force expire an IAM connection' )
346
345
}
347
- const provider = this . getTokenProvider ( conn . id , profile )
346
+ const provider = this . getSsoTokenProvider ( conn . id , profile )
348
347
await provider . invalidate ( )
349
348
// updates the state of the connection
350
- await this . validateConnection ( conn . id , profile )
349
+ await this . refreshConnectionState ( conn )
351
350
}
352
351
353
352
public async getConnection ( connection : Pick < Connection , 'id' > ) : Promise < Connection | undefined > {
@@ -460,7 +459,7 @@ export class Auth implements AuthService, ConnectionManager {
460
459
const profile = this . store . getProfileOrThrow ( id )
461
460
462
461
if ( profile . type === 'sso' ) {
463
- const provider = this . getTokenProvider ( id , profile )
462
+ const provider = this . getSsoTokenProvider ( id , profile )
464
463
const client = this . createSsoClient ( profile . ssoRegion , provider )
465
464
466
465
if ( opt ?. skipGlobalLogout !== true ) {
@@ -506,7 +505,7 @@ export class Auth implements AuthService, ConnectionManager {
506
505
private async validateConnection < T extends Profile > ( id : Connection [ 'id' ] , profile : StoredProfile < T > ) {
507
506
const runCheck = async ( ) => {
508
507
if ( profile . type === 'sso' ) {
509
- const provider = this . getTokenProvider ( id , profile )
508
+ const provider = this . getSsoTokenProvider ( id , profile )
510
509
if ( ( await provider . getToken ( ) ) === undefined ) {
511
510
getLogger ( ) . info ( `auth: Connection is not valid: ${ id } ` )
512
511
return this . updateConnectionState ( id , 'invalid' )
@@ -540,10 +539,13 @@ export class Auth implements AuthService, ConnectionManager {
540
539
}
541
540
}
542
541
543
- return runCheck ( ) . catch ( err => this . handleValidationError ( id , err ) )
542
+ return runCheck ( ) . catch ( err => this . handleSsoTokenError ( id , err ) )
544
543
}
545
544
546
- private async handleValidationError ( id : Connection [ 'id' ] , err : unknown ) {
545
+ private async handleSsoTokenError ( id : Connection [ 'id' ] , err : unknown ) {
546
+ // Bubble-up networking issues so we don't treat the session as invalid
547
+ this . throwOnNetworkError ( err )
548
+
547
549
this . #validationErrors. set ( id , UnknownError . cast ( err ) )
548
550
getLogger ( ) . info ( `auth: Handling validation error of connection: ${ id } ` )
549
551
return this . updateConnectionState ( id , 'invalid' )
@@ -579,7 +581,7 @@ export class Auth implements AuthService, ConnectionManager {
579
581
throw new Error ( `Source profile for "${ id } " is not an SSO profile` )
580
582
}
581
583
582
- const tokenProvider = this . getTokenProvider ( profile . ssoSession , sourceProfile )
584
+ const tokenProvider = this . getSsoTokenProvider ( profile . ssoSession , sourceProfile )
583
585
const credentialsProvider = new SsoCredentialsProvider (
584
586
fromString ( id ) ,
585
587
this . createSsoClient ( sourceProfile . ssoRegion , tokenProvider ) ,
@@ -630,7 +632,7 @@ export class Auth implements AuthService, ConnectionManager {
630
632
: [ identifier , createSsoProfile ( region , startUrl , scopesCodeCatalyst ) ]
631
633
}
632
634
633
- private getTokenProvider ( id : Connection [ 'id' ] , profile : StoredProfile < SsoProfile > ) {
635
+ private getSsoTokenProvider ( id : Connection [ 'id' ] , profile : StoredProfile < SsoProfile > ) {
634
636
// XXX: Use the token created by Dev Environments if and only if the profile is strictly
635
637
// for CodeCatalyst, as indicated by its set of scopes. A consequence of these semantics is
636
638
// that any profile will be coerced to use this token if that profile exclusively contains
@@ -642,7 +644,7 @@ export class Auth implements AuthService, ConnectionManager {
642
644
643
645
const tokenIdentifier = shouldUseSoftwareStatement ? this . detectSsoSessionNameForCodeCatalyst ( ) : id
644
646
645
- return this . createTokenProvider (
647
+ return this . createSsoTokenProvider (
646
648
{
647
649
identifier : tokenIdentifier ,
648
650
startUrl : profile . startUrl ,
@@ -671,7 +673,7 @@ export class Auth implements AuthService, ConnectionManager {
671
673
id : Connection [ 'id' ] ,
672
674
profile : StoredProfile < SsoProfile >
673
675
) : SsoConnection & StatefulConnection {
674
- const provider = this . getTokenProvider ( id , profile )
676
+ const provider = this . getSsoTokenProvider ( id , profile )
675
677
676
678
return {
677
679
id,
@@ -692,7 +694,7 @@ export class Auth implements AuthService, ConnectionManager {
692
694
693
695
return result
694
696
} catch ( err ) {
695
- await this . handleValidationError ( id , err )
697
+ await this . handleSsoTokenError ( id , err )
696
698
throw err
697
699
}
698
700
}
@@ -717,18 +719,29 @@ export class Auth implements AuthService, ConnectionManager {
717
719
private async _getToken ( id : Connection [ 'id' ] , provider : SsoAccessTokenProvider ) : Promise < SsoToken > {
718
720
const token = await provider . getToken ( ) . catch ( err => {
719
721
// Bubble-up networking issues so we don't treat the session as invalid
720
- if ( isNetworkError ( err ) ) {
721
- throw new ToolkitError ( 'Failed to refresh connection due to networking issues' , {
722
- cause : err ,
723
- } )
724
- }
722
+ this . throwOnNetworkError ( err )
725
723
726
724
this . #validationErrors. set ( id , err )
727
725
} )
728
726
729
727
return token ?? this . handleInvalidCredentials ( id , ( ) => provider . createToken ( ) )
730
728
}
731
729
730
+ /**
731
+ * Auth processes can fail if there are network issues, and we do not
732
+ * want to intepret these failures as invalid/expired auth tokens.
733
+ *
734
+ * We use this to check if the given error is network related and then
735
+ * throw, expecting the caller to not change the state of the connection.
736
+ */
737
+ private throwOnNetworkError ( e : unknown ) {
738
+ if ( isNetworkError ( e ) ) {
739
+ throw new ToolkitError ( 'Failed to update connection due to networking issues' , {
740
+ cause : e ,
741
+ } )
742
+ }
743
+ }
744
+
732
745
private readonly getCredentials = keyedDebounce ( this . _getCredentials . bind ( this ) )
733
746
private async _getCredentials ( id : Connection [ 'id' ] , provider : CredentialsProvider ) : Promise < Credentials > {
734
747
const credentials = await this . getCachedCredentials ( provider )
0 commit comments