Skip to content

Commit

Permalink
fix(auth): logout flow gets triggered for auth check network failures (
Browse files Browse the repository at this point in the history
  • Loading branch information
griest024 committed Jul 26, 2023
1 parent 2100b24 commit 7d6b62d
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 8 deletions.
23 changes: 23 additions & 0 deletions libs/auth/routing/src/guards/guest-only.guard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { DaffAuthStorageService } from '@daffodil/auth';
import {
DaffAuthDriverTokenCheck,
DaffAuthInvalidAPIResponseError,
DaffAuthenticationFailedError,
DaffUnauthorizedError,
} from '@daffodil/auth/driver';
import { DaffAuthGuardLogout } from '@daffodil/auth/state';
Expand Down Expand Up @@ -122,6 +123,28 @@ describe('@daffodil/auth/routing | GuestOnlyGuard', () => {
expect(mockStore.dispatch).toHaveBeenCalledWith(jasmine.any(DaffAuthGuardLogout));
});
});

describe('from an unauthenticated error', () => {
beforeEach(() => {
daffAuthCheckService.check.and.returnValue(hot('--#', {}, new DaffAuthenticationFailedError('error')));
result = guard.canActivate();
expected = cold('--(b|)', { b: true });
});

it('should return true', () => {
expect(result).toBeObservable(expected);
});

it('should remove the token from storage', () => {
expect(result).toBeObservable(expected);
expect(daffAuthStorageService.removeAuthToken).toHaveBeenCalledWith();
});

it('should dispatch guard logout', () => {
expect(result).toBeObservable(expected);
expect(mockStore.dispatch).toHaveBeenCalledWith(jasmine.any(DaffAuthGuardLogout));
});
});
});
});
});
2 changes: 1 addition & 1 deletion libs/auth/routing/src/guards/guest-only.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class GuestOnlyGuard implements CanActivate {
return this.tokenCheck.check().pipe(
map(() => false),
catchError((error: DaffError) => {
if (error.code === DaffAuthDriverErrorCodes.UNAUTHORIZED) {
if (error.code === DaffAuthDriverErrorCodes.UNAUTHORIZED || error.code === DaffAuthDriverErrorCodes.AUTHENTICATION_FAILED) {
this.storage.removeAuthToken();
this.store.dispatch(new DaffAuthGuardLogout(this.errorMatcher(error)));
}
Expand Down
23 changes: 23 additions & 0 deletions libs/auth/routing/src/guards/member-only.guard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { DaffAuthStorageService } from '@daffodil/auth';
import {
DaffAuthDriverTokenCheck,
DaffAuthInvalidAPIResponseError,
DaffAuthenticationFailedError,
DaffUnauthorizedError,
} from '@daffodil/auth/driver';
import { DaffAuthGuardLogout } from '@daffodil/auth/state';
Expand Down Expand Up @@ -122,6 +123,28 @@ describe('@daffodil/auth/routing | MemberOnlyGuard', () => {
expect(mockStore.dispatch).toHaveBeenCalledWith(jasmine.any(DaffAuthGuardLogout));
});
});

describe('from an unauthenticated error', () => {
beforeEach(() => {
daffAuthCheckService.check.and.returnValue(hot('--#', {}, new DaffAuthenticationFailedError('error')));
result = guard.canActivate();
expected = cold('--(b|)', { b: false });
});

it('should return false', () => {
expect(result).toBeObservable(expected);
});

it('should remove the token from storage', () => {
expect(result).toBeObservable(expected);
expect(daffAuthStorageService.removeAuthToken).toHaveBeenCalledWith();
});

it('should dispatch guard logout', () => {
expect(result).toBeObservable(expected);
expect(mockStore.dispatch).toHaveBeenCalledWith(jasmine.any(DaffAuthGuardLogout));
});
});
});
});
});
2 changes: 1 addition & 1 deletion libs/auth/routing/src/guards/member-only.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class MemberOnlyGuard implements CanActivate {
return this.tokenCheck.check().pipe(
map(() => true),
catchError((error: DaffError) => {
if (error.code === DaffAuthDriverErrorCodes.UNAUTHORIZED) {
if (error.code === DaffAuthDriverErrorCodes.UNAUTHORIZED || error.code === DaffAuthDriverErrorCodes.AUTHENTICATION_FAILED) {
this.storage.removeAuthToken();
this.store.dispatch(new DaffAuthGuardLogout(this.errorMatcher(error)));
}
Expand Down
26 changes: 21 additions & 5 deletions libs/auth/state/src/effects/auth.effects.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import { TestScheduler } from 'rxjs/testing';
import { DaffAuthStorageService } from '@daffodil/auth';
import {
DaffAuthDriver,
DaffAuthInvalidAPIResponseError,
DaffAuthServiceInterface,
DaffAuthenticationFailedError,
DaffUnauthorizedError,
} from '@daffodil/auth/driver';
import {
DaffAuthCheck,
Expand Down Expand Up @@ -214,20 +216,34 @@ describe('@daffodil/auth/state | DaffAuthEffects', () => {
describe('resetToUnauthenticated$', () => {
let expected;

describe('when AuthCheckFailure is dispatched', () => {
let authLogoutSuccessAction: DaffAuthCheckFailure;
describe('when DaffAuthCheckFailure is dispatched for an unauthorized error', () => {
let revokeAction: DaffAuthCheckFailure;

beforeEach(() => {
authLogoutSuccessAction = new DaffAuthCheckFailure({ code: 'code', message: 'message' });
actions$ = hot('--a', { a: authLogoutSuccessAction });
expected = cold('--a', { a: new DaffAuthResetToUnauthenticated(authLogoutSuccessAction.type) });
revokeAction = new DaffAuthCheckFailure(new DaffUnauthorizedError('error'));
actions$ = hot('--a', { a: revokeAction });
expected = cold('--a', { a: new DaffAuthResetToUnauthenticated(revokeAction.type) });
});

it('should dispatch DaffAuthResetToUnauthenticated', () => {
expect(effects.resetToUnauthenticated$).toBeObservable(expected);
});
});

describe('when DaffAuthCheckFailure is dispatched for some random reason', () => {
let revokeAction: DaffAuthCheckFailure;

beforeEach(() => {
revokeAction = new DaffAuthCheckFailure(new DaffAuthInvalidAPIResponseError(''));
actions$ = hot('---');
expected = cold('---');
});

it('should not dispatch DaffAuthResetToUnauthenticated', () => {
expect(effects.resetToUnauthenticated$).toBeObservable(expected);
});
});

describe('when AuthGuardLogout is dispatched', () => {
let authLogoutSuccessAction: DaffAuthGuardLogout;

Expand Down
17 changes: 16 additions & 1 deletion libs/auth/state/src/effects/auth.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ import {
DaffAuthStorageService,
DAFF_AUTH_ERROR_MATCHER,
} from '@daffodil/auth';
import { DaffAuthDriverTokenCheck } from '@daffodil/auth/driver';
import {
DaffAuthDriverErrorCodes,
DaffAuthDriverTokenCheck,
} from '@daffodil/auth/driver';
import {
DaffError,
DaffServerSideStorageError,
Expand Down Expand Up @@ -123,6 +126,18 @@ export class DaffAuthEffects {
DaffAuthActionTypes.AuthGuardLogoutAction,
DaffAuthLoginActionTypes.LogoutSuccessAction,
),
filter((action) => {
// if the auth check failure is for any reason other than auth failure, don't reset
if (
action.type === DaffAuthActionTypes.AuthCheckFailureAction
&& action.errorMessage.code !== DaffAuthDriverErrorCodes.UNAUTHORIZED
&& action.errorMessage.code !== DaffAuthDriverErrorCodes.AUTHENTICATION_FAILED
) {
return false;
}

return true;
}),
map((action) => new DaffAuthResetToUnauthenticated(action.type)),
));

Expand Down

0 comments on commit 7d6b62d

Please sign in to comment.