1. create session if not instant popup if refresh fails
2. add optimization to not call refresh session twice 3. add unit test Signed-off-by: Gasan Guseinov <gasan.guseinov@ing.com>
This commit is contained in:
committed by
Gasan.Guseinov
parent
5ddc0fedb0
commit
7bf209736d
@@ -275,4 +275,26 @@ describe('RefreshingAuthSessionManager', () => {
|
||||
expect(refreshSession).toHaveBeenCalledTimes(1);
|
||||
expect(createSession).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should create a new session if refresh fails with existing expired session', async () => {
|
||||
const createSession = jest.fn();
|
||||
const refreshSession = jest.fn().mockRejectedValue(new Error('NOPE'));
|
||||
const manager = new RefreshingAuthSessionManager({
|
||||
connector: { createSession, refreshSession },
|
||||
...defaultOptions,
|
||||
} as any);
|
||||
|
||||
createSession.mockResolvedValue({
|
||||
scopes: new Set(['a']),
|
||||
expired: true,
|
||||
});
|
||||
await manager.getSession({ scopes: new Set(['a']) });
|
||||
expect(refreshSession).toHaveBeenCalledTimes(1);
|
||||
expect(createSession).toHaveBeenCalledTimes(1);
|
||||
|
||||
await manager.getSession({ scopes: new Set(['a']) });
|
||||
// call refresh session only once
|
||||
expect(refreshSession).toHaveBeenCalledTimes(2);
|
||||
expect(createSession).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -64,6 +64,7 @@ export class RefreshingAuthSessionManager<T> implements SessionManager<T> {
|
||||
}
|
||||
|
||||
async getSession(options: GetSessionOptions): Promise<T | undefined> {
|
||||
let alreadyTriedToRefreshSession = false;
|
||||
if (
|
||||
this.helper.sessionExistsAndHasScope(this.currentSession, options.scopes)
|
||||
) {
|
||||
@@ -72,6 +73,8 @@ export class RefreshingAuthSessionManager<T> implements SessionManager<T> {
|
||||
return this.currentSession!;
|
||||
}
|
||||
|
||||
alreadyTriedToRefreshSession = true;
|
||||
|
||||
try {
|
||||
const refreshedSession = await this.collapsedSessionRefresh(
|
||||
options.scopes,
|
||||
@@ -83,7 +86,20 @@ export class RefreshingAuthSessionManager<T> implements SessionManager<T> {
|
||||
}
|
||||
return refreshedSession;
|
||||
} catch (error) {
|
||||
// If the refresh attempt fails we assume we don't have a session, so continue to create one.
|
||||
this.removeLocalSession();
|
||||
|
||||
if (options.optional) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (options.instantPopup) {
|
||||
// if `instantPopup`, then can't continue because
|
||||
// we are in asynchronous control flow. Therefore, the application must not try to
|
||||
// open the popup later in `connector#createSession(...)` because the browser may block the popup.
|
||||
// Immediately return error.
|
||||
throw error;
|
||||
}
|
||||
// If the refresh attempt fails we assume we don't have a session, so continue to create one
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,13 +110,14 @@ export class RefreshingAuthSessionManager<T> implements SessionManager<T> {
|
||||
// stay in a synchronous call stack from the user interaction. The downside
|
||||
// is that the user will sometimes be requested to log in even if they
|
||||
// already had an existing session.
|
||||
if (!options.instantPopup) {
|
||||
if (!options.instantPopup && !alreadyTriedToRefreshSession) {
|
||||
try {
|
||||
const newSession = await this.collapsedSessionRefresh(options.scopes);
|
||||
this.currentSession = newSession;
|
||||
// The session might not have the scopes requested so go back and check again
|
||||
return this.getSession(options);
|
||||
} catch {
|
||||
this.removeLocalSession();
|
||||
// If the refresh attempt fails we assume we don't have a session, so continue to create one.
|
||||
}
|
||||
}
|
||||
@@ -119,6 +136,18 @@ export class RefreshingAuthSessionManager<T> implements SessionManager<T> {
|
||||
return this.currentSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets `undefined` to this.{@link currentSession} and tells this.{@link stateTracker}, session state tracker,
|
||||
* that a user has signed out.
|
||||
*
|
||||
* Does not propagate session removal to the connector like {@link removeSession}().
|
||||
*
|
||||
*/
|
||||
removeLocalSession() {
|
||||
this.currentSession = undefined;
|
||||
this.stateTracker.setIsSignedIn(false);
|
||||
}
|
||||
|
||||
async removeSession() {
|
||||
this.currentSession = undefined;
|
||||
await this.connector.removeSession();
|
||||
|
||||
Reference in New Issue
Block a user