@bcweed/authentication-lib 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.editorconfig +17 -0
  2. package/AngularAuthenticationLibrary.esproj +10 -0
  3. package/CHANGELOG.md +16 -0
  4. package/README.md +59 -0
  5. package/angular.json +66 -0
  6. package/obj/Debug/AngularAuthenticationLibrary.esproj.CoreCompileInputs.cache +0 -0
  7. package/obj/Debug/AngularAuthenticationLibrary.esproj.FileListAbsolute.txt +1 -0
  8. package/obj/Debug/package.g.props +52 -0
  9. package/package.json +61 -0
  10. package/projects/authentication-lib/README.md +63 -0
  11. package/projects/authentication-lib/ng-package.json +7 -0
  12. package/projects/authentication-lib/package.json +27 -0
  13. package/projects/authentication-lib/src/lib/auth-callback/auth-callback.component.html +1 -0
  14. package/projects/authentication-lib/src/lib/auth-callback/auth-callback.component.scss +0 -0
  15. package/projects/authentication-lib/src/lib/auth-callback/auth-callback.component.spec.ts +23 -0
  16. package/projects/authentication-lib/src/lib/auth-callback/auth-callback.component.ts +68 -0
  17. package/projects/authentication-lib/src/lib/auth.service.spec.ts +16 -0
  18. package/projects/authentication-lib/src/lib/auth.service.ts +213 -0
  19. package/projects/authentication-lib/src/lib/authentication-error/authentication-error.component.html +7 -0
  20. package/projects/authentication-lib/src/lib/authentication-error/authentication-error.component.scss +0 -0
  21. package/projects/authentication-lib/src/lib/authentication-error/authentication-error.component.spec.ts +23 -0
  22. package/projects/authentication-lib/src/lib/authentication-error/authentication-error.component.ts +32 -0
  23. package/projects/authentication-lib/src/lib/authentication-lib.module.ts +26 -0
  24. package/projects/authentication-lib/src/lib/authentication-lib.tokens.ts +4 -0
  25. package/projects/authentication-lib/src/lib/login/login.component.html +1 -0
  26. package/projects/authentication-lib/src/lib/login/login.component.scss +0 -0
  27. package/projects/authentication-lib/src/lib/login/login.component.spec.ts +23 -0
  28. package/projects/authentication-lib/src/lib/login/login.component.ts +28 -0
  29. package/projects/authentication-lib/src/lib/login-menu/login-menu.component.html +39 -0
  30. package/projects/authentication-lib/src/lib/login-menu/login-menu.component.scss +7 -0
  31. package/projects/authentication-lib/src/lib/login-menu/login-menu.component.spec.ts +23 -0
  32. package/projects/authentication-lib/src/lib/login-menu/login-menu.component.ts +51 -0
  33. package/projects/authentication-lib/src/lib/logout/logout.component.html +1 -0
  34. package/projects/authentication-lib/src/lib/logout/logout.component.scss +0 -0
  35. package/projects/authentication-lib/src/lib/logout/logout.component.spec.ts +23 -0
  36. package/projects/authentication-lib/src/lib/logout/logout.component.ts +29 -0
  37. package/projects/authentication-lib/src/lib/logout-callback/logout-callback.component.html +0 -0
  38. package/projects/authentication-lib/src/lib/logout-callback/logout-callback.component.scss +0 -0
  39. package/projects/authentication-lib/src/lib/logout-callback/logout-callback.component.spec.ts +23 -0
  40. package/projects/authentication-lib/src/lib/logout-callback/logout-callback.component.ts +27 -0
  41. package/projects/authentication-lib/src/lib/route-history.service.spec.ts +16 -0
  42. package/projects/authentication-lib/src/lib/route-history.service.ts +31 -0
  43. package/projects/authentication-lib/src/public-api.ts +14 -0
  44. package/projects/authentication-lib/tsconfig.lib.json +15 -0
  45. package/projects/authentication-lib/tsconfig.lib.prod.json +11 -0
  46. package/projects/authentication-lib/tsconfig.spec.json +15 -0
  47. package/tsconfig.json +32 -0
@@ -0,0 +1,213 @@
1
+ import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
2
+ import { isPlatformBrowser } from '@angular/common';
3
+ import { OAuthService, OAuthErrorEvent, OAuthEvent, AuthConfig } from 'angular-oauth2-oidc';
4
+ import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
5
+ import { Router } from '@angular/router';
6
+ import { BehaviorSubject, combineLatest, map, Observable, ReplaySubject, Subject } from 'rxjs';
7
+ import { AUTHENTICATION_LIB_CONFIG } from './authentication-lib.tokens';
8
+ //import { authConfig } from './auth.config';
9
+ export interface UserProfile {
10
+ sub: string;
11
+ name?: string;
12
+ email?: string;
13
+ preferred_username?: string;
14
+ given_name?: string;
15
+ family_name?: string;
16
+ fax?: string;
17
+ address?: string;
18
+ address2?: string;
19
+ city?: string;
20
+ region?: string;
21
+ country?: string;
22
+ phone_number?: string;
23
+ postal_code?: string;
24
+ [key: string]: any;
25
+ }
26
+
27
+ @Injectable({ providedIn: 'root' })
28
+ export class AuthService {
29
+ constructor(@Inject(AUTHENTICATION_LIB_CONFIG) private readonly authConfig: AuthConfig,
30
+ private oauthService: OAuthService,
31
+ private router: Router,
32
+ @Inject(PLATFORM_ID) private platformId: object) {
33
+ if (isPlatformBrowser(this.platformId)) {
34
+ this.oauthService.configure(authConfig);
35
+ this.oauthService.tokenValidationHandler = new JwksValidationHandler(); // Auto-handles redirect back
36
+
37
+ this.oauthService.events
38
+ .subscribe(_ => {
39
+ this.isAuthenticatedSubject$.next(this.oauthService.hasValidAccessToken());
40
+ });
41
+ this.oauthService.events.subscribe(e => this.handleOAuthEvent(e));
42
+
43
+ this.oauthService.setupAutomaticSilentRefresh(); }
44
+
45
+ }
46
+ private readonly profile$ = new BehaviorSubject<UserProfile | null>(null);
47
+ private profileLoading = false;
48
+ private profileIsLoaded = false;
49
+ private isAuthenticatedSubject$ = new BehaviorSubject<boolean>(false);
50
+ public isAuthenticated$ = this.isAuthenticatedSubject$.asObservable();
51
+
52
+ private isDoneLoadingSubject$ = new ReplaySubject<boolean>();
53
+ public isDoneLoading$ = this.isDoneLoadingSubject$.asObservable();
54
+
55
+ private eventsSubject$ = new Subject<OAuthEvent>;
56
+ public events$ = this.eventsSubject$.asObservable();
57
+ /**
58
+ * Publishes `true` if and only if (a) all the asynchronous initial
59
+ * login calls have completed or errored, and (b) the user ended up
60
+ * being authenticated.
61
+ *
62
+ * In essence, it combines:
63
+ *
64
+ * - the latest known state of whether the user is authorized
65
+ * - whether the ajax calls for initial log in have all been done
66
+ */
67
+ public isLoggedIn$: Observable<boolean> = combineLatest([
68
+ this.isAuthenticated$,
69
+ this.isDoneLoading$
70
+ ]).pipe(map(values => values.every(b => b)));
71
+
72
+ public runInitialLoginSequence(): Promise<void> {
73
+ return this.oauthService.loadDiscoveryDocument()
74
+ .then(() => this.oauthService.tryLoginCodeFlow())
75
+ .then(() => {
76
+ this.isDoneLoadingSubject$.next(true);
77
+ // remove query params
78
+ //this.router.navigate(['']);
79
+ })
80
+ .catch(() => this.isDoneLoadingSubject$.next(true));
81
+ }
82
+
83
+ public login(returnUrl: string): void {
84
+ // Triggers redirect to IdP with PKCE code challenge
85
+ this.oauthService.initCodeFlow(returnUrl); // Authorization Code + PKCE
86
+ }
87
+
88
+ logout(): void {
89
+ this.oauthService.logOut(); // Optionally also call revocation endpoint
90
+ }
91
+ revokeTokenAndLogout(): void {
92
+ this.oauthService.revokeTokenAndLogout({
93
+ idTokenHint: this.oauthService.getIdToken(),
94
+ client_id: this.authConfig.clientId,
95
+ returnTo: this.authConfig.postLogoutRedirectUri
96
+ }, true); // Optionally also call revocation endpoint
97
+ }
98
+
99
+ public state(): string | undefined {
100
+ return this.oauthService.state;
101
+ }
102
+ public hasRole(role: string) {
103
+ let claims: any = this.oauthService.getIdentityClaims();
104
+ if (claims && claims.role) {
105
+ let roles: string[] = claims.role;
106
+ roles = roles.map(role => role.toUpperCase());
107
+ return roles.includes(role.toLocaleUpperCase());
108
+ }
109
+ return false;
110
+ }
111
+ public refresh() {
112
+ this.oauthService.silentRefresh();
113
+ }
114
+
115
+ public hasValidToken() {
116
+ return this.oauthService.hasValidAccessToken();
117
+ }
118
+
119
+ public getFullname() {
120
+ let claims: any = this.oauthService.getIdentityClaims();
121
+ if (claims && claims.name) {
122
+ return claims.name;
123
+ }
124
+ return undefined;
125
+ }
126
+ get accessToken(): string {
127
+ return this.oauthService.getAccessToken();
128
+ }
129
+
130
+ get identityClaims(): any {
131
+ return this.oauthService.getIdentityClaims();
132
+ }
133
+
134
+ get isLoggedIn(): boolean {
135
+ return !!this.accessToken;
136
+ }
137
+
138
+ get userProfile$() {
139
+ return this.profile$.asObservable();
140
+ }
141
+
142
+ /** Synchronous getter */
143
+ get snapshot(): UserProfile | null {
144
+ return this.profile$.value;
145
+ }
146
+
147
+ /** Clears profile on logout */
148
+ clearProfile() {
149
+ this.profile$.next(null);
150
+ this.profileIsLoaded = false;
151
+ }
152
+
153
+ /** Loads user profile from userinfo endpoint */
154
+ async loadProfile(): Promise<void> {
155
+ if (this.profileIsLoaded) return;
156
+ if (this.profileLoading) return;
157
+ if (!this.oauthService.hasValidAccessToken()) return;
158
+
159
+ this.profileLoading = true;
160
+
161
+ try {
162
+ const profile: any = await this.oauthService.loadUserProfile();
163
+ const info = profile?.info ?? null;
164
+ this.profile$.next(info);
165
+ this.profileIsLoaded = true;
166
+
167
+ } catch (err) {
168
+ console.warn('User profile load failed:', err);
169
+ // swallow error — do not let Angular ErrorHandler see it
170
+ } finally {
171
+ this.profileLoading = false;
172
+ }
173
+ }
174
+
175
+ /** Handles OAuth events */
176
+ private handleOAuthEvent(e: OAuthEvent) {
177
+ this.eventsSubject$.next(e);
178
+ switch (e.type) {
179
+ case 'token_received':
180
+ this.loadProfile();
181
+ break;
182
+
183
+ case 'discovery_document_loaded':
184
+ if (this.oauthService.hasValidAccessToken()) {
185
+ this.loadProfile();
186
+ }
187
+ break;
188
+ case 'user_profile_loaded':
189
+ // Some IdPs trigger this event automatically
190
+ // this.loadProfile();
191
+ break;
192
+
193
+ case 'logout':
194
+ case 'session_terminated':
195
+ case 'session_error':
196
+ this.clearProfile();
197
+ break;
198
+
199
+ case 'silent_refresh_error':
200
+ case 'silent_refresh_timeout':
201
+ console.log(e);
202
+ throw new Error(e.type);
203
+ break;
204
+
205
+ default:
206
+ // Swallow OAuth errors before Angular sees them
207
+ if (e instanceof OAuthErrorEvent) {
208
+ console.warn('OAuth error intercepted:', e);
209
+ }
210
+ break;
211
+ }
212
+ }
213
+ }
@@ -0,0 +1,7 @@
1
+ <p>authentication-error works!</p>
2
+
3
+ <button [routerLink]="['/auth/login']" [queryParams]="{ returnUrl: routeParams$ | async }">Retry Login</button>
4
+ <br />
5
+ <button [routerLink]="['/home']">Go Home</button>
6
+ @if (routeParams$ | async) {
7
+ }
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { AuthenticationErrorComponent } from './authentication-error.component';
4
+
5
+ describe('AuthenticationErrorComponent', () => {
6
+ let component: AuthenticationErrorComponent;
7
+ let fixture: ComponentFixture<AuthenticationErrorComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [AuthenticationErrorComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(AuthenticationErrorComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,32 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, OnInit } from '@angular/core';
3
+ import { ActivatedRoute, RouterModule } from '@angular/router';
4
+ import { Observable } from 'rxjs';
5
+ import { map, tap } from 'rxjs/operators';
6
+
7
+ @Component({
8
+ selector: 'app-authentication-error',
9
+ imports: [CommonModule,RouterModule],
10
+ standalone: true,
11
+ templateUrl: './authentication-error.component.html',
12
+ styleUrl: './authentication-error.component.scss'
13
+ })
14
+ export class AuthenticationErrorComponent implements OnInit {
15
+ constructor(private activatedRoute: ActivatedRoute) { }
16
+ routeParams$: Observable<any> | undefined;
17
+ returnUrl: string | undefined;
18
+ ngOnInit(): void {
19
+
20
+ this.routeParams$ = this.activatedRoute.queryParams.pipe(
21
+ map(params => {
22
+ if (params['returnUrl']) {
23
+
24
+ return params['returnUrl'];
25
+ }
26
+ else {
27
+ return '/';
28
+ }
29
+ })
30
+ );
31
+ }
32
+ }
@@ -0,0 +1,26 @@
1
+ import { NgModule, ModuleWithProviders, APP_INITIALIZER } from '@angular/core';
2
+ import { AuthConfig } from 'angular-oauth2-oidc';
3
+ import { AUTHENTICATION_LIB_CONFIG } from './authentication-lib.tokens';
4
+ import { CommonModule } from '@angular/common';
5
+ import { RouterModule } from '@angular/router';
6
+ import { RouteHistoryService } from './route-history.service';
7
+
8
+ @NgModule({
9
+ declarations: [],
10
+ imports: [
11
+ CommonModule,
12
+ RouterModule
13
+ ],
14
+ exports: [],
15
+ providers: [
16
+ {
17
+ provide: APP_INITIALIZER,
18
+ useFactory: (history: RouteHistoryService) => () => history.init(),
19
+ deps: [RouteHistoryService],
20
+ multi: true
21
+ },
22
+
23
+ ]
24
+ })
25
+ export class AuthenticationLibModule {
26
+ }
@@ -0,0 +1,4 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import { AuthConfig } from 'angular-oauth2-oidc';
3
+
4
+ export const AUTHENTICATION_LIB_CONFIG = new InjectionToken<AuthConfig>('AUTHENTICATION_LIB_CONFIG');
@@ -0,0 +1 @@
1
+ <p>Redirecting!!!!</p>
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { LoginComponent } from './login.component';
4
+
5
+ describe('LoginComponent', () => {
6
+ let component: LoginComponent;
7
+ let fixture: ComponentFixture<LoginComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ declarations: [LoginComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(LoginComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,28 @@
1
+ import { Component, OnInit } from '@angular/core';
2
+ import { ActivatedRoute } from '@angular/router';
3
+ import { AuthService } from '../auth.service';
4
+ import { RouteHistoryService } from '../route-history.service';
5
+ import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
6
+ import { isPlatformBrowser } from '@angular/common';
7
+
8
+ @Component({
9
+ selector: 'app-login',
10
+ standalone: true,
11
+ imports: [],
12
+ templateUrl: './login.component.html',
13
+ styleUrl: './login.component.scss'
14
+ })
15
+ export class LoginComponent implements OnInit {
16
+
17
+ constructor(private activatedRoute: ActivatedRoute, private routeHistoryService: RouteHistoryService, private authService: AuthService,
18
+ @Inject(PLATFORM_ID) private platformId: object) { }
19
+ ngOnInit() {
20
+ debugger;
21
+ if (isPlatformBrowser(this.platformId)) {
22
+ const rt = this.activatedRoute;
23
+ const returnUrl = rt.snapshot.queryParams['returnUrl'] || this.routeHistoryService.getPreviousUrl() || '/';
24
+ this.authService.login(returnUrl);
25
+ }
26
+ }
27
+
28
+ }
@@ -0,0 +1,39 @@
1
+ @if ((isAuthenticated$ | async) === true) {
2
+ <ul role="menu" [ngClass]="[isSmallMedia ? 'p-menubar-root-list-end-small' : 'p-menubar-root-list']">
3
+ <li role="menuitem" ptooltip="" class="p-element p-menubar-item">
4
+ <div class="p-menubar-item-content">
5
+ <a class="p-ripple p-element p-menubar-item-link" [routerLink]='["/auth/logout", ]' [state]='{ local: true }'>
6
+ <span class="p-menubar-item-icon pi pi-sign-out"></span>
7
+ <span class="p-menubar-item-label">Logout</span>
8
+ </a>
9
+ </div>
10
+ </li>
11
+ <li role="menuitem" ptooltip="" class="p-element p-menubar-item">
12
+ <div class="p-menubar-item-content">
13
+ <a class="p-ripple p-element p-menubar-item-link" [routerLink]='["/authentication/profile"]'>
14
+ <span class="p-menubar-item-icon pi pi-user"></span>
15
+ <span class="p-menubar-item-label">{{ (profile$ | async)?.given_name}} {{ (profile$ | async)?.family_name}}</span>
16
+ </a>
17
+ </div>
18
+ </li>
19
+ </ul>
20
+ }
21
+ @if ((isAuthenticated$ | async) !== true) {
22
+ <ul role="menu" [ngClass]="[isSmallMedia ? 'p-menubar-root-list-end-small' : 'p-menubar-root-list']">
23
+ <!--<li role="menuitem" ptooltip="" class="p-element p-menuitem">
24
+ <div class="p-menubar-item-content">
25
+ <a pripple="" class="p-ripple p-element p-menubar-item-link" [routerLink]='["/authentication/register"]'>
26
+ <span class="p-menubar-item-label">Register</span>
27
+ </a>
28
+ </div>
29
+ </li>-->
30
+ <li role="menuitem" ptooltip="" class="p-element p-menubar-item">
31
+ <div class="p-menubar-item-content">
32
+ <a pripple="" class="p-ripple p-element p-menubar-item-link" [routerLink]='["/auth/login"]'>
33
+ <span class="p-menubar-item-icon pi pi-sign-in"></span>
34
+ <span class="p-menubar-item-label">Login</span>
35
+ </a>
36
+ </div>
37
+ </li>
38
+ </ul>
39
+ }
@@ -0,0 +1,7 @@
1
+ .p-menubar-item {
2
+ display: inline-block!important;
3
+ }
4
+
5
+ .p-menubar-root-list-end-small{
6
+
7
+ }
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { LoginMenuComponent } from './login-menu.component';
4
+
5
+ describe('LoginMenuComponent', () => {
6
+ let component: LoginMenuComponent;
7
+ let fixture: ComponentFixture<LoginMenuComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [LoginMenuComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(LoginMenuComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,51 @@
1
+ import { Component } from '@angular/core';
2
+ import { from, Observable } from 'rxjs';
3
+ import { CommonModule } from '@angular/common';
4
+ import {RouterModule } from '@angular/router';
5
+ import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
6
+ import { MenuItem } from 'primeng/api';
7
+ import { AuthService, UserProfile } from '../auth.service';
8
+
9
+ @Component({
10
+ selector: 'app-login-menu',
11
+ standalone: true,
12
+ imports: [CommonModule, RouterModule], // Add them to the imports array
13
+ templateUrl: './login-menu.component.html',
14
+ styleUrl: './login-menu.component.scss'
15
+ })
16
+ export class LoginMenuComponent {
17
+
18
+ isExpanded = false;
19
+ isSmallMedia = false;
20
+ userRoles: string[] = [];
21
+ items: MenuItem[] | undefined;
22
+ public isAuthenticated?: boolean;
23
+ profile$: Observable<UserProfile | null>;
24
+ isAuthenticated$: Observable<boolean | null> | undefined;
25
+ constructor(private responsive: BreakpointObserver, private authService: AuthService) {
26
+ this.profile$ = this.authService.userProfile$;
27
+ this.isAuthenticated$ = this.authService.isAuthenticated$;
28
+ }
29
+ ngOnInit() {
30
+ this.responsive.observe([Breakpoints.Small, Breakpoints.XSmall])
31
+ .subscribe(result => {
32
+
33
+
34
+ if (result.matches) {
35
+ this.isSmallMedia = true;
36
+
37
+ }
38
+ else {
39
+ this.isSmallMedia = false;
40
+
41
+ }
42
+ });
43
+ }
44
+ collapse() {
45
+ this.isExpanded = false;
46
+ }
47
+
48
+ toggle() {
49
+ this.isExpanded = !this.isExpanded;
50
+ }
51
+ }
@@ -0,0 +1 @@
1
+ <p>Redirecting!!!!</p>
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { LogoutComponent } from './logout.component';
4
+
5
+ describe('LogoutComponent', () => {
6
+ let component: LogoutComponent;
7
+ let fixture: ComponentFixture<LogoutComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [LogoutComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(LogoutComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,29 @@
1
+ import { Component, OnInit, } from '@angular/core';
2
+ import { AuthService } from '../auth.service';
3
+ import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
4
+ import { isPlatformBrowser } from '@angular/common';
5
+
6
+ @Component({
7
+ selector: 'app-logout',
8
+ standalone: true,
9
+ imports: [],
10
+ templateUrl: './logout.component.html',
11
+ styleUrl: './logout.component.scss'
12
+ })
13
+ export class LogoutComponent implements OnInit {
14
+
15
+ constructor(private authService: AuthService,
16
+ @Inject(PLATFORM_ID) private platformId: object) { }
17
+ ngOnInit() {
18
+ //this.authService.logout();
19
+ if (isPlatformBrowser(this.platformId)) {
20
+ this.authService.revokeTokenAndLogout();
21
+ }
22
+
23
+ // Clear local storage
24
+ //localStorage.clear();
25
+ //sessionStorage.clear();
26
+ ////this.authService.revokeTokenAndLogout();
27
+ }
28
+
29
+ }
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { LogoutCallbackComponent } from './logout-callback.component';
4
+
5
+ describe('LogoutCallbackComponent', () => {
6
+ let component: LogoutCallbackComponent;
7
+ let fixture: ComponentFixture<LogoutCallbackComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [LogoutCallbackComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(LogoutCallbackComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -0,0 +1,27 @@
1
+
2
+ import { Component, OnInit } from '@angular/core';
3
+ import { Router } from '@angular/router';
4
+ import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
5
+ import { isPlatformBrowser } from '@angular/common';
6
+
7
+ @Component({
8
+ selector: 'app-logout-callback',
9
+ imports: [],
10
+ standalone:true,
11
+ templateUrl: './logout-callback.component.html',
12
+ styleUrl: './logout-callback.component.scss'
13
+ })
14
+ export class LogoutCallbackComponent implements OnInit {
15
+ constructor(private router: Router,
16
+ @Inject(PLATFORM_ID) private platformId: object) { }
17
+
18
+ ngOnInit(): void {
19
+ if (isPlatformBrowser(this.platformId)) {
20
+ localStorage.clear();
21
+ sessionStorage.clear();
22
+
23
+ this.router.navigate(['/home']);
24
+ }
25
+
26
+ }
27
+ }
@@ -0,0 +1,16 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+
3
+ import { RouteHistoryService } from './route-history.service';
4
+
5
+ describe('RouteHistoryService', () => {
6
+ let service: RouteHistoryService;
7
+
8
+ beforeEach(() => {
9
+ TestBed.configureTestingModule({});
10
+ service = TestBed.inject(RouteHistoryService);
11
+ });
12
+
13
+ it('should be created', () => {
14
+ expect(service).toBeTruthy();
15
+ });
16
+ });
@@ -0,0 +1,31 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
3
+ import { filter} from 'rxjs/operators';
4
+
5
+
6
+ @Injectable({
7
+ providedIn: 'root'
8
+ })
9
+ export class RouteHistoryService {
10
+
11
+ private previousUrl: string | null = null;
12
+ private currentUrl: string | null = null;
13
+
14
+ constructor(private router: Router, private activatedRoute:ActivatedRoute) { }
15
+
16
+ init() {
17
+ this.currentUrl = this.router.url;
18
+
19
+ this.router.events
20
+ .pipe(filter(event => event instanceof NavigationEnd))
21
+ .subscribe((event: NavigationEnd) => {
22
+ this.previousUrl = this.currentUrl;
23
+ this.currentUrl = event.urlAfterRedirects;
24
+ });
25
+ }
26
+
27
+ getPreviousUrl(): string | null {
28
+ return this.previousUrl;
29
+ }
30
+
31
+ }