Skip to content

Commit

Permalink
chore: added token revocation
Browse files Browse the repository at this point in the history
  • Loading branch information
yosvelquintero committed Nov 28, 2023
1 parent 32b744d commit 8d99521
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 12 deletions.
1 change: 1 addition & 0 deletions packages/core/config/src/lib/constants/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ import { IApiConstant } from '@console-core/types';
export const API: Readonly<IApiConstant> = {
endpoints: {
token: '/token',
tokenRevocation: '/token/revocation',
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ export class AccountEffects {

resetAccountState$ = createEffect(() => {
return this.actions$.pipe(
ofType(authnActions.signOut),
ofType(authnActions.signOutSuccess, authnActions.signOutFail),
map(() => accountActions.resetAccountState())
);
});
Expand Down
14 changes: 12 additions & 2 deletions packages/core/state/src/lib/+state/authn/authn.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,19 @@ export const confirmPasswordFail = createAction(
props<{ error: string }>()
);

export const signOut = createAction(
'[AUTHN] Sign out',
export const signOutRequest = createAction(
'[AUTHN] Sign out request',
props<{ payload: { showNotification: boolean } }>()
);

export const signOutSuccess = createAction(
'[AUTHN] Sign out success',
props<{ payload: { showNotification: boolean } }>()
);

export const signOutFail = createAction(
'[AUTHN] Sign out fail',
props<{ error: string; showNotification: boolean }>()
);

export const resetAuthnState = createAction('[AUTHN] Reset authn state');
43 changes: 37 additions & 6 deletions packages/core/state/src/lib/+state/authn/authn.effects.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Actions, createEffect, ofType, concatLatestFrom } from '@ngrx/effects';
import { catchError, map, of, switchMap, take, tap } from 'rxjs';

import { ROUTER } from '@console-core/config';
Expand All @@ -11,6 +11,7 @@ import { AccountFacade } from '../account';
import { AppFacade } from '../app';

import * as authnActions from './authn.actions';
import { AuthnFacade } from './authn.facade';

@Injectable()
export class AuthnEffects {
Expand Down Expand Up @@ -251,12 +252,41 @@ export class AuthnEffects {
{ dispatch: false }
);

signOut$ = createEffect(
signOutRequest$ = createEffect(() => {
return this.actions$.pipe(
ofType(authnActions.signOutRequest),
concatLatestFrom(() => this.authnFacade.token$),
switchMap(([{ payload }, token]) => {
if (!token) {
return of(
authnActions.signOutFail({
error: 'your token is invalid',
showNotification: payload.showNotification,
})
);
}

return this.authnService.signOut({ token }).pipe(
map(() => authnActions.signOutSuccess({ payload })),
catchError((error: Error) =>
of(
authnActions.signOutFail({
error: error.message,
showNotification: payload.showNotification,
})
)
)
);
})
);
});

signOut = createEffect(
() => {
return this.actions$.pipe(
ofType(authnActions.signOut),
tap(({ payload }) => {
if (payload.showNotification) {
ofType(authnActions.signOutSuccess, authnActions.signOutFail),
tap((action) => {
if ('payload' in action && action.payload.showNotification) {
this.appFacade.addNotification({
content: 'signed out',
type: ENotificationTypes.SUCCESS,
Expand Down Expand Up @@ -299,7 +329,7 @@ export class AuthnEffects {

resetAuthnState$ = createEffect(() => {
return this.actions$.pipe(
ofType(authnActions.signOut),
ofType(authnActions.signOutSuccess, authnActions.signOutFail),
map(() => authnActions.resetAuthnState())
);
});
Expand All @@ -311,6 +341,7 @@ export class AuthnEffects {
private readonly authnService: AuthnService,
private readonly userService: UserService,
private readonly appFacade: AppFacade,
private readonly authnFacade: AuthnFacade,
private readonly accountFacade: AccountFacade
) {}
}
2 changes: 1 addition & 1 deletion packages/core/state/src/lib/+state/authn/authn.facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class AuthnFacade {
this.store.dispatch(authnActions.signInRequest({ payload }));
signOut = (showNotification = true) =>
this.store.dispatch(
authnActions.signOut({
authnActions.signOutRequest({
payload: { showNotification },
})
);
Expand Down
18 changes: 17 additions & 1 deletion packages/core/state/src/lib/+state/authn/authn.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,29 @@ const reducer = createReducer<IAuthnState>(
})
),
on(
authnActions.signOut,
authnActions.signOutRequest,
(state): IAuthnState => ({
...state,
actionStatus: EActionStatus.REQUESTING,
})
),
on(
authnActions.signOutSuccess,
(state): IAuthnState => ({
...state,
isAuthenticated: false,
actionStatus: EActionStatus.SUCCEEDED,
})
),
on(
authnActions.signOutFail,
(state, { error }): IAuthnState => ({
...state,
isAuthenticated: false,
actionStatus: EActionStatus.FAILED,
error,
})
),
on(
authnActions.resetAuthnState,
(_): IAuthnState => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const reducer = createReducer<ICountryState>(
countryActions.countryReadRequest,
(state): ICountryState => ({
...state,
actionStatus: EActionStatus.CREATED,
actionStatus: EActionStatus.REQUESTING,
})
),
on(
Expand Down
13 changes: 13 additions & 0 deletions packages/core/state/src/lib/services/identity/authn.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import {
IAuthnTokenSignInPayload,
IAuthnTokenSignInResponse,
IAuthnTokenSignOutPayload,
} from '@console-core/types';

import { ApiService } from '../api.service';
Expand Down Expand Up @@ -53,4 +54,16 @@ export class AuthnService {
}
);
}

signOut(payload: IAuthnTokenSignOutPayload): Observable<unknown> {
const body = new URLSearchParams();
body.set('token', payload.token);
return this.httpClient.post(
this.apiService.getEndpoint('tokenRevocation'),
body.toString(),
{
headers: this.headers,
}
);
}
}
1 change: 1 addition & 0 deletions packages/core/types/src/lib/interfaces/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export interface IApiConstant {
readonly endpoints: {
readonly token: string;
readonly tokenRevocation: string;
};
}
4 changes: 4 additions & 0 deletions packages/core/types/src/lib/interfaces/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export interface IAuthnTokenSignInPayload {
password?: string;
}

export interface IAuthnTokenSignOutPayload {
token: string;
}

export interface IAuthnTokenSignInResponse {
access_token?: string;
id_token?: string;
Expand Down

0 comments on commit 8d99521

Please sign in to comment.