Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion packages/passport/sdk/src/authManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ describe('AuthManager', () => {
let mockStoreUser: jest.Mock;
let mockOverlayAppend: jest.Mock;
let mockOverlayRemove: jest.Mock;
let mockRevokeTokens: jest.Mock;

beforeEach(() => {
mockSigninPopup = jest.fn();
Expand All @@ -106,6 +107,7 @@ describe('AuthManager', () => {
mockStoreUser = jest.fn();
mockOverlayAppend = jest.fn();
mockOverlayRemove = jest.fn();
mockRevokeTokens = jest.fn();
(UserManager as jest.Mock).mockReturnValue({
signinPopup: mockSigninPopup,
signinCallback: mockSigninCallback,
Expand All @@ -115,6 +117,7 @@ describe('AuthManager', () => {
getUser: mockGetUser,
signinSilent: mockSigninSilent,
storeUser: mockStoreUser,
revokeTokens: mockRevokeTokens,
});
(Overlay as jest.Mock).mockReturnValue({
append: mockOverlayAppend,
Expand All @@ -140,11 +143,13 @@ describe('AuthManager', () => {
userinfo_endpoint: `${config.authenticationDomain}/userinfo`,
end_session_endpoint: `${config.authenticationDomain}${logoutEndpoint}`
+ `?client_id=${config.oidcConfiguration.clientId}`,
revocation_endpoint: `${config.authenticationDomain}/oauth/revoke`,
},
popup_redirect_uri: config.oidcConfiguration.popupRedirectUri,
redirect_uri: config.oidcConfiguration.redirectUri,
scope: config.oidcConfiguration.scope,
userStore: expect.any(WebStorageStateStore),
revokeTokenTypes: ['refresh_token'],
});
});

Expand All @@ -159,6 +164,7 @@ describe('AuthManager', () => {
extraQueryParams: {
audience: configWithAudience.oidcConfiguration.audience,
},
revokeTokenTypes: ['refresh_token'],
}));
});
});
Expand Down Expand Up @@ -391,6 +397,7 @@ describe('AuthManager', () => {

await manager.logout();

expect(mockRevokeTokens).toHaveBeenCalledWith(['refresh_token']);
expect(mockSignoutRedirect).toBeCalled();
});

Expand All @@ -402,6 +409,7 @@ describe('AuthManager', () => {

await manager.logout();

expect(mockRevokeTokens).toHaveBeenCalledWith(['refresh_token']);
expect(mockSignoutRedirect).toBeCalled();
});

Expand All @@ -413,10 +421,46 @@ describe('AuthManager', () => {

await manager.logout();

expect(mockRevokeTokens).toHaveBeenCalledWith(['refresh_token']);
expect(mockSignoutSilent).toBeCalled();
});

it('should throw an error if user is failed to logout', async () => {
describe('when revoking of refresh tokens fails', () => {
it('should throw an error for redirect logout', async () => {
const configuration = getConfig({
logoutMode: 'redirect',
});
const manager = new AuthManager(configuration);
mockRevokeTokens.mockRejectedValue(new Error(mockErrorMsg));

await expect(() => manager.logout()).rejects.toThrow(
new PassportError(
mockErrorMsg,
PassportErrorType.LOGOUT_ERROR,
),
);
expect(mockSignoutRedirect).not.toHaveBeenCalled();
});

it('should throw an error for silent logout', async () => {
const configuration = getConfig({
logoutMode: 'silent',
});
const manager = new AuthManager(configuration);
mockRevokeTokens.mockRejectedValue(new Error(mockErrorMsg));

await expect(() => manager.logout()).rejects.toThrow(
new PassportError(
mockErrorMsg,
PassportErrorType.LOGOUT_ERROR,
),
);
// In silent mode, signoutSilent is called in parallel with revokeTokens
expect(mockSignoutSilent).toHaveBeenCalled();
});
});

it('should throw an error if user is failed to logout with redirect', async () => {
const configuration = getConfig({
logoutMode: 'redirect',
});
Expand All @@ -430,6 +474,24 @@ describe('AuthManager', () => {
PassportErrorType.LOGOUT_ERROR,
),
);
expect(mockRevokeTokens).toHaveBeenCalledWith(['refresh_token']);
});

it('should throw an error if user is failed to logout silently', async () => {
const configuration = getConfig({
logoutMode: 'silent',
});
const manager = new AuthManager(configuration);

mockSignoutSilent.mockRejectedValue(new Error(mockErrorMsg));

await expect(() => manager.logout()).rejects.toThrow(
new PassportError(
mockErrorMsg,
PassportErrorType.LOGOUT_ERROR,
),
);
expect(mockRevokeTokens).toHaveBeenCalledWith(['refresh_token']);
});
});

Expand Down
22 changes: 13 additions & 9 deletions packages/passport/sdk/src/authManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,13 @@ const getAuthConfiguration = (config: PassportConfiguration): UserManagerSetting
token_endpoint: `${authenticationDomain}/oauth/token`,
userinfo_endpoint: `${authenticationDomain}/userinfo`,
end_session_endpoint: endSessionEndpoint.toString(),
revocation_endpoint: `${authenticationDomain}/oauth/revoke`,
},
mergeClaims: true,
automaticSilentRenew: false, // Disabled until https://github.com/authts/oidc-client-ts/issues/430 has been resolved
scope: oidcConfiguration.scope,
userStore,
revokeTokenTypes: ['refresh_token'],
extraQueryParams: {
...config.extraQueryParams,
...(oidcConfiguration.audience ? { audience: oidcConfiguration.audience } : {}),
Expand Down Expand Up @@ -436,15 +438,17 @@ export default class AuthManager {
}

public async logout(): Promise<void> {
return withPassportError<void>(
async () => {
if (this.logoutMode === 'silent') {
return this.userManager.signoutSilent();
}
return this.userManager.signoutRedirect();
},
PassportErrorType.LOGOUT_ERROR,
);
return withPassportError<void>(async () => {
if (this.logoutMode === 'silent') {
await Promise.all([
this.userManager.revokeTokens(['refresh_token']),
this.userManager.signoutSilent(),
]);
} else {
await this.userManager.revokeTokens(['refresh_token']);
await this.userManager.signoutRedirect();
}
}, PassportErrorType.LOGOUT_ERROR);
}

public async logoutSilentCallback(url: string): Promise<void> {
Expand Down