@@ -94,6 +94,7 @@ describe('AuthManager', () => {
9494 let mockStoreUser : jest . Mock ;
9595 let mockOverlayAppend : jest . Mock ;
9696 let mockOverlayRemove : jest . Mock ;
97+ let mockRevokeTokens : jest . Mock ;
9798
9899 beforeEach ( ( ) => {
99100 mockSigninPopup = jest . fn ( ) ;
@@ -106,6 +107,7 @@ describe('AuthManager', () => {
106107 mockStoreUser = jest . fn ( ) ;
107108 mockOverlayAppend = jest . fn ( ) ;
108109 mockOverlayRemove = jest . fn ( ) ;
110+ mockRevokeTokens = jest . fn ( ) ;
109111 ( UserManager as jest . Mock ) . mockReturnValue ( {
110112 signinPopup : mockSigninPopup ,
111113 signinCallback : mockSigninCallback ,
@@ -115,6 +117,9 @@ describe('AuthManager', () => {
115117 getUser : mockGetUser ,
116118 signinSilent : mockSigninSilent ,
117119 storeUser : mockStoreUser ,
120+ removeUser : jest . fn ( ) ,
121+ clearStaleState : jest . fn ( ) ,
122+ revokeTokens : mockRevokeTokens ,
118123 } ) ;
119124 ( Overlay as jest . Mock ) . mockReturnValue ( {
120125 append : mockOverlayAppend ,
@@ -140,11 +145,13 @@ describe('AuthManager', () => {
140145 userinfo_endpoint : `${ config . authenticationDomain } /userinfo` ,
141146 end_session_endpoint : `${ config . authenticationDomain } ${ logoutEndpoint } `
142147 + `?client_id=${ config . oidcConfiguration . clientId } ` ,
148+ revocation_endpoint : `${ config . authenticationDomain } /oauth/revoke` ,
143149 } ,
144150 popup_redirect_uri : config . oidcConfiguration . popupRedirectUri ,
145151 redirect_uri : config . oidcConfiguration . redirectUri ,
146152 scope : config . oidcConfiguration . scope ,
147153 userStore : expect . any ( WebStorageStateStore ) ,
154+ revokeTokenTypes : [ 'refresh_token' ] ,
148155 } ) ;
149156 } ) ;
150157
@@ -383,53 +390,91 @@ describe('AuthManager', () => {
383390 } ) ;
384391
385392 describe ( 'logout' , ( ) => {
386- it ( 'should call redirect logout if logout mode is redirect' , async ( ) => {
387- const configuration = getConfig ( {
388- logoutMode : 'redirect' ,
389- } ) ;
390- const manager = new AuthManager ( configuration ) ;
391-
392- await manager . logout ( ) ;
393-
394- expect ( mockSignoutRedirect ) . toBeCalled ( ) ;
393+ it ( 'should revoke refresh token and call signoutRedirect by default' , async ( ) => {
394+ mockGetUser . mockResolvedValue ( mockOidcUser ) ;
395+ await authManager . logout ( ) ;
396+ expect ( mockGetUser ) . toHaveBeenCalledTimes ( 1 ) ;
397+ expect ( mockRevokeTokens ) . toHaveBeenCalledWith ( [ 'refresh_token' ] ) ;
398+ expect ( mockSignoutRedirect ) . toHaveBeenCalledTimes ( 1 ) ;
399+ expect ( mockSignoutSilent ) . not . toHaveBeenCalled ( ) ;
395400 } ) ;
396401
397- it ( 'should call redirect logout if logout mode is not set' , async ( ) => {
398- const configuration = getConfig ( {
399- logoutMode : undefined ,
400- } ) ;
401- const manager = new AuthManager ( configuration ) ;
402+ it ( 'should call signoutSilent when logoutMode is silent' , async ( ) => {
403+ const silentLogoutConfig = getConfig ( { logoutMode : 'silent' } ) ;
404+ authManager = new AuthManager ( silentLogoutConfig ) ;
405+ mockGetUser . mockResolvedValue ( mockOidcUser ) ;
402406
403- await manager . logout ( ) ;
407+ await authManager . logout ( ) ;
404408
405- expect ( mockSignoutRedirect ) . toBeCalled ( ) ;
409+ expect ( mockGetUser ) . toHaveBeenCalledTimes ( 1 ) ;
410+ expect ( mockRevokeTokens ) . toHaveBeenCalledWith ( [ 'refresh_token' ] ) ;
411+ expect ( mockSignoutSilent ) . toHaveBeenCalledTimes ( 1 ) ;
412+ expect ( mockSignoutRedirect ) . not . toHaveBeenCalled ( ) ;
406413 } ) ;
407414
408- it ( 'should call silent logout if logout mode is silent' , async ( ) => {
409- const configuration = getConfig ( {
410- logoutMode : 'silent' ,
411- } ) ;
412- const manager = new AuthManager ( configuration ) ;
415+ it ( 'should not call revokeTokens if user has no refresh token' , async ( ) => {
416+ const userWithoutRefreshToken = { ...mockOidcUser , refresh_token : undefined } ;
417+ mockGetUser . mockResolvedValue ( userWithoutRefreshToken ) ;
418+ await authManager . logout ( ) ;
419+ expect ( mockGetUser ) . toHaveBeenCalledTimes ( 1 ) ;
420+ expect ( mockRevokeTokens ) . not . toHaveBeenCalled ( ) ;
421+ expect ( mockSignoutRedirect ) . toHaveBeenCalledTimes ( 1 ) ;
422+ } ) ;
423+
424+ it ( 'should not call revokeTokens or signout methods if no user is found' , async ( ) => {
425+ mockGetUser . mockResolvedValue ( null ) ;
426+ await authManager . logout ( ) ;
427+ expect ( mockGetUser ) . toHaveBeenCalledTimes ( 1 ) ;
428+ expect ( mockRevokeTokens ) . not . toHaveBeenCalled ( ) ;
429+ expect ( mockSignoutRedirect ) . not . toHaveBeenCalled ( ) ;
430+ expect ( mockSignoutSilent ) . not . toHaveBeenCalled ( ) ;
431+ } ) ;
413432
414- await manager . logout ( ) ;
433+ it ( 'should throw PassportError if revokeTokens fails' , async ( ) => {
434+ mockGetUser . mockResolvedValue ( mockOidcUser ) ;
435+ const revokeError = new Error ( 'Revoke failed' ) ;
436+ mockRevokeTokens . mockRejectedValue ( revokeError ) ;
415437
416- expect ( mockSignoutSilent ) . toBeCalled ( ) ;
438+ await expect ( authManager . logout ( ) ) . rejects . toThrow (
439+ new PassportError (
440+ revokeError . message ,
441+ PassportErrorType . LOGOUT_ERROR ,
442+ ) ,
443+ ) ;
444+ expect ( mockRevokeTokens ) . toHaveBeenCalledWith ( [ 'refresh_token' ] ) ;
445+ expect ( mockSignoutRedirect ) . not . toHaveBeenCalled ( ) ;
417446 } ) ;
418447
419- it ( 'should throw an error if user is failed to logout' , async ( ) => {
420- const configuration = getConfig ( {
421- logoutMode : 'redirect' ,
422- } ) ;
423- const manager = new AuthManager ( configuration ) ;
448+ it ( 'should throw PassportError if signoutRedirect fails' , async ( ) => {
449+ mockGetUser . mockResolvedValue ( mockOidcUser ) ;
450+ const signOutError = new Error ( 'Signout failed' ) ;
451+ mockSignoutRedirect . mockRejectedValue ( signOutError ) ;
452+
453+ await expect ( authManager . logout ( ) ) . rejects . toThrow (
454+ new PassportError (
455+ signOutError . message ,
456+ PassportErrorType . LOGOUT_ERROR ,
457+ ) ,
458+ ) ;
459+ expect ( mockRevokeTokens ) . toHaveBeenCalledWith ( [ 'refresh_token' ] ) ;
460+ expect ( mockSignoutRedirect ) . toHaveBeenCalledTimes ( 1 ) ;
461+ } ) ;
424462
425- mockSignoutRedirect . mockRejectedValue ( new Error ( mockErrorMsg ) ) ;
463+ it ( 'should throw PassportError if signoutSilent fails' , async ( ) => {
464+ const silentLogoutConfig = getConfig ( { logoutMode : 'silent' } ) ;
465+ authManager = new AuthManager ( silentLogoutConfig ) ;
466+ mockGetUser . mockResolvedValue ( mockOidcUser ) ;
467+ const signOutError = new Error ( 'Signout silent failed' ) ;
468+ mockSignoutSilent . mockRejectedValue ( signOutError ) ;
426469
427- await expect ( ( ) => manager . logout ( ) ) . rejects . toThrow (
470+ await expect ( authManager . logout ( ) ) . rejects . toThrow (
428471 new PassportError (
429- mockErrorMsg ,
472+ signOutError . message ,
430473 PassportErrorType . LOGOUT_ERROR ,
431474 ) ,
432475 ) ;
476+ expect ( mockRevokeTokens ) . toHaveBeenCalledWith ( [ 'refresh_token' ] ) ;
477+ expect ( mockSignoutSilent ) . toHaveBeenCalledTimes ( 1 ) ;
433478 } ) ;
434479 } ) ;
435480
@@ -473,7 +518,7 @@ describe('AuthManager', () => {
473518
474519 await expect ( ( ) => authManager . getUser ( ) ) . rejects . toThrow (
475520 new PassportError (
476- 'Failed to refresh token: oops: Failed to remove user: this.userManager.removeUser is not a function ' ,
521+ 'Failed to refresh token: oops' ,
477522 PassportErrorType . AUTHENTICATION_ERROR ,
478523 ) ,
479524 ) ;
0 commit comments