@@ -107,6 +107,7 @@ export class OAuthService extends AuthConfig implements OnDestroy {
107107 protected sessionCheckTimer : any ;
108108 protected silentRefreshSubject : string ;
109109 protected inImplicitFlow = false ;
110+ protected lastUpdatedAccessToken : string | null = null ;
110111
111112 protected saveNoncesInLocalStorage = false ;
112113 private document : Document ;
@@ -171,6 +172,10 @@ export class OAuthService extends AuthConfig implements OnDestroy {
171172 }
172173
173174 this . setupRefreshTimer ( ) ;
175+
176+ if ( this . hasValidAccessToken ( ) ) {
177+ this . lastUpdatedAccessToken = this . getAccessToken ( ) ;
178+ }
174179 }
175180
176181 private checkLocalStorageAccessable ( ) {
@@ -927,6 +932,27 @@ export class OAuthService extends AuthConfig implements OnDestroy {
927932 * method silentRefresh.
928933 */
929934 public refreshToken ( ) : Promise < TokenResponse > {
935+ // Handle multiple browser tabs if navigator.locks is available
936+ if ( ! navigator . locks ) {
937+ return this . _refreshToken ( ) ;
938+ }
939+ return navigator . locks . request (
940+ `refresh_token_${ location . origin } ` ,
941+ async ( ) : Promise < TokenResponse > => {
942+ if ( this . lastUpdatedAccessToken !== this . getAccessToken ( ) ) {
943+ // Was already updated in another tab/window
944+ this . eventsSubject . next ( new OAuthSuccessEvent ( 'token_received' ) ) ;
945+ this . eventsSubject . next ( new OAuthSuccessEvent ( 'token_refreshed' ) ) ;
946+ this . lastUpdatedAccessToken = this . getAccessToken ( ) ;
947+ return ;
948+ } else {
949+ // Simply run the original update
950+ return this . _refreshToken ( ) ;
951+ }
952+ }
953+ ) ;
954+ }
955+ protected _refreshToken ( ) : Promise < TokenResponse > {
930956 this . assertUrlNotNullAndCorrectProtocol (
931957 this . tokenEndpoint ,
932958 'tokenEndpoint'
@@ -1051,6 +1077,32 @@ export class OAuthService extends AuthConfig implements OnDestroy {
10511077 public silentRefresh (
10521078 params : object = { } ,
10531079 noPrompt = true
1080+ ) : Promise < OAuthEvent > {
1081+ // Handle multiple browser tabs if navigator.locks is available
1082+ if ( ! navigator . locks ) {
1083+ return this . _silentRefresh ( params , noPrompt ) ;
1084+ }
1085+ return navigator . locks . request (
1086+ `silent_refresh_${ location . origin } ` ,
1087+ async ( ) : Promise < OAuthEvent > => {
1088+ if ( this . lastUpdatedAccessToken !== this . getAccessToken ( ) ) {
1089+ // Was already updated in another tab/window
1090+ this . eventsSubject . next ( new OAuthSuccessEvent ( 'token_received' ) ) ;
1091+ this . eventsSubject . next ( new OAuthSuccessEvent ( 'token_refreshed' ) ) ;
1092+ const event = new OAuthSuccessEvent ( 'silently_refreshed' ) ;
1093+ this . eventsSubject . next ( event ) ;
1094+ this . lastUpdatedAccessToken = this . getAccessToken ( ) ;
1095+ return event ;
1096+ } else {
1097+ // Simply run the original update
1098+ return this . _silentRefresh ( params , noPrompt ) ;
1099+ }
1100+ }
1101+ ) ;
1102+ }
1103+ protected _silentRefresh (
1104+ params : object = { } ,
1105+ noPrompt = true
10541106 ) : Promise < OAuthEvent > {
10551107 const claims : object = this . getIdentityClaims ( ) || { } ;
10561108
@@ -1677,6 +1729,7 @@ export class OAuthService extends AuthConfig implements OnDestroy {
16771729 customParameters ?: Map < string , string >
16781730 ) : void {
16791731 this . _storage . setItem ( 'access_token' , accessToken ) ;
1732+ this . lastUpdatedAccessToken = accessToken ;
16801733 if ( grantedScopes && ! Array . isArray ( grantedScopes ) ) {
16811734 this . _storage . setItem (
16821735 'granted_scopes' ,
@@ -2496,6 +2549,7 @@ export class OAuthService extends AuthConfig implements OnDestroy {
24962549
24972550 const id_token = this . getIdToken ( ) ;
24982551 this . _storage . removeItem ( 'access_token' ) ;
2552+ this . lastUpdatedAccessToken = null ;
24992553 this . _storage . removeItem ( 'id_token' ) ;
25002554 this . _storage . removeItem ( 'refresh_token' ) ;
25012555
0 commit comments