From 531cb738ee1f8fdf1caf12e50d8f6c9aa103a5a4 Mon Sep 17 00:00:00 2001
From: Martin <git@mail.de>
Date: Fri, 17 Jan 2025 17:43:21 +0100
Subject: [PATCH 1/5] OZG-6986 OZG-7509 adjust authentication service

---
 .../src/lib/authentication.service.spec.ts    | 236 +++++++++++++++++-
 .../src/lib/authentication.service.ts         |  56 ++++-
 .../authentication/test/authentication.ts     |   7 +-
 3 files changed, 283 insertions(+), 16 deletions(-)

diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
index bd176bb914..1ef750f989 100644
--- a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
@@ -23,30 +23,39 @@
  */
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { UserProfileResource } from '@alfa-client/user-profile-shared';
+import { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc';
+import { Environment } from 'libs/environment-shared/src/lib/environment.model';
 import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
-import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
-import { AuthenticationService } from './authentication.service';
-import { createAuthConfig } from '../../test/authentication';
+import { Subject } from 'rxjs';
 import { createEnvironment } from '../../../environment-shared/test/environment';
-import { Environment } from 'libs/environment-shared/src/lib/environment.model';
+import { createAuthConfig, createOAuthEvent } from '../../test/authentication';
+import { AuthenticationService } from './authentication.service';
 
 describe('AuthenticationService', () => {
   let service: AuthenticationService;
   let oAuthService: Mock<OAuthService>;
   let environmentConfig: Environment;
 
+  let eventsSubject: Subject<OAuthEvent>;
+
   beforeEach(() => {
+    eventsSubject = new Subject<OAuthEvent>();
+
     oAuthService = <any>{
       ...mock(OAuthService),
       loadDiscoveryDocumentAndLogin: jest.fn().mockResolvedValue(() => Promise.resolve()),
+      hasValidAccessToken: jest.fn(),
+      hasValidIdToken: jest.fn(),
     };
+    Object.defineProperty(oAuthService, 'events', { get: () => eventsSubject });
+
     environmentConfig = createEnvironment();
     service = new AuthenticationService(useFromMock(oAuthService), environmentConfig);
   });
 
   describe('login', () => {
     beforeEach(() => {
-      service.setCurrentUser = jest.fn();
+      service.buildEventPromise = jest.fn();
     });
 
     it('should configure service with authConfig', async () => {
@@ -72,16 +81,227 @@ describe('AuthenticationService', () => {
       expect(oAuthService.tokenValidationHandler).not.toBeNull();
     });
 
+    it('should build event promise', async () => {
+      service.buildEventPromise = jest.fn().mockResolvedValue(() => Promise.resolve());
+
+      await service.login();
+
+      expect(service.buildEventPromise).toHaveBeenCalled();
+    });
+
     it('should load discovery document and login', () => {
       service.login();
 
       expect(oAuthService.loadDiscoveryDocumentAndLogin).toHaveBeenCalled();
     });
 
-    it('should set current user', async () => {
-      await service.login();
+    it('should return eventPromise', async () => {
+      const promise: Promise<void> = Promise.resolve();
+      service.buildEventPromise = jest.fn().mockResolvedValue(promise);
+
+      const returnPromise: Promise<void> = service.login();
+
+      await expect(returnPromise).resolves.toBeUndefined();
+    });
+  });
+
+  describe('build event promise', () => {
+    const event: OAuthEvent = createOAuthEvent();
+
+    beforeEach(() => {
+      service.shouldProceed = jest.fn().mockReturnValue(true);
+      service.setCurrentUser = jest.fn();
+      service.unsubscribeEvents = jest.fn();
+    });
+
+    it('should call shouldProceed on event trigger', () => {
+      service.buildEventPromise();
+      eventsSubject.next(event);
+
+      expect(service.shouldProceed).toHaveBeenCalledWith(event);
+    });
+
+    describe('on next', () => {
+      it('should set current user', () => {
+        service.buildEventPromise();
+        eventsSubject.next(event);
+
+        expect(service.setCurrentUser).toHaveBeenCalled();
+      });
+
+      it('should unsubscribe event', () => {
+        service.buildEventPromise();
+        eventsSubject.next(event);
+
+        expect(service.unsubscribeEvents).toHaveBeenCalled();
+      });
+
+      it('should resolved promise with a valid event', async () => {
+        const promise: Promise<void> = service.buildEventPromise();
+        eventsSubject.next(event);
+
+        await expect(promise).resolves.toBeUndefined();
+      });
+    });
+
+    describe('on error', () => {
+      const errorMessage: string = 'Test Error';
+      const error: Error = new Error(errorMessage);
+
+      it('should unsubscribe event', () => {
+        service.buildEventPromise();
+        eventsSubject.error(error);
+
+        expect(service.unsubscribeEvents).toHaveBeenCalled();
+      });
+
+      it('should reject the promise with an error', async () => {
+        const promise: Promise<void> = service.buildEventPromise();
+
+        eventsSubject.error(error);
+
+        await expect(promise).rejects.toThrow(errorMessage);
+      });
+    });
+  });
+
+  describe('should proceed', () => {
+    const event: OAuthEvent = createOAuthEvent();
+
+    it('should call considered as login event', () => {
+      service.consideredAsLoginEvent = jest.fn();
+
+      service.shouldProceed(event);
+
+      expect(service.consideredAsLoginEvent).toHaveBeenCalledWith(event.type);
+    });
+
+    it('should return true on login event', () => {
+      service.consideredAsLoginEvent = jest.fn().mockReturnValue(true);
+
+      const proceed: boolean = service.shouldProceed(event);
+
+      expect(proceed).toBeTruthy();
+    });
+
+    it('should call considered as page reload event', () => {
+      service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
+      service.consideredAsPageReloadEvent = jest.fn();
+
+      service.shouldProceed(event);
+
+      expect(service.consideredAsPageReloadEvent).toHaveBeenCalledWith(event.type);
+    });
+
+    it('should return true on page reload event', () => {
+      service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
+      service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(true);
+
+      const proceed: boolean = service.shouldProceed(event);
+
+      expect(proceed).toBeTruthy();
+    });
+
+    it('should return false on non login or page reload event', () => {
+      service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
+      service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(false);
+
+      const proceed: boolean = service.shouldProceed(event);
+
+      expect(proceed).toBeFalsy();
+    });
+  });
+
+  describe('consideredAsLoginEvent', () => {
+    it('should return true if event is "token_received"', () => {
+      const event: string = 'token_received';
+
+      const result: boolean = service.consideredAsLoginEvent(event);
+
+      expect(result).toBeTruthy();
+    });
+
+    it('should return false if event is not "token_received"', () => {
+      const event: string = 'something_else';
+
+      const result: boolean = service.consideredAsLoginEvent(event);
+
+      expect(result).toBeFalsy();
+    });
+  });
+
+  describe('consideredAsPageReloadEvent', () => {
+    it('should return true if event is "discovery_document_loaded" and tokens are valid', () => {
+      service.hasValidToken = jest.fn().mockReturnValue(true);
+      const event: string = 'discovery_document_loaded';
+
+      const result: boolean = service.consideredAsPageReloadEvent(event);
+
+      expect(result).toBeTruthy();
+    });
+
+    it('should return false if event is "discovery_document_loaded" and tokens are invalid', () => {
+      service.hasValidToken = jest.fn().mockReturnValue(false);
+      const event: string = 'discovery_document_loaded';
+
+      const result: boolean = service.consideredAsPageReloadEvent(event);
+
+      expect(result).toBeFalsy();
+    });
+
+    it('should return false if event is not "discovery_document_loaded" and tokens are valid', () => {
+      service.hasValidToken = jest.fn().mockReturnValue(true);
+      const event: string = 'something_else';
+
+      const result: boolean = service.consideredAsPageReloadEvent(event);
+
+      expect(result).toBeFalsy();
+    });
+
+    it('should return false if event is not "discovery_document_loaded" and tokens are invalid', () => {
+      service.hasValidToken = jest.fn().mockReturnValue(false);
+      const event: string = 'something_else';
+
+      const result: boolean = service.consideredAsPageReloadEvent(event);
+
+      expect(result).toBeFalsy();
+    });
+  });
+
+  describe('hasValidToken', () => {
+    it('should return true if both tokens are valid', () => {
+      oAuthService.hasValidAccessToken.mockReturnValue(true);
+      oAuthService.hasValidIdToken.mockReturnValue(true);
+
+      const result: boolean = service.hasValidToken();
+
+      expect(result).toBeTruthy();
+    });
+
+    it('should return false if access token is invalid', () => {
+      oAuthService.hasValidAccessToken.mockReturnValue(false);
+
+      const result: boolean = service.hasValidToken();
+
+      expect(result).toBeFalsy();
+    });
+
+    it('should return false if id token is invalid', () => {
+      oAuthService.hasValidAccessToken.mockReturnValue(true);
+      oAuthService.hasValidIdToken.mockReturnValue(false);
+
+      const result: boolean = service.hasValidToken();
+
+      expect(result).toBeFalsy();
+    });
+
+    it('should return false if both tokens are invalid', () => {
+      oAuthService.hasValidAccessToken.mockReturnValue(false);
+      oAuthService.hasValidIdToken.mockReturnValue(false);
+
+      const result: boolean = service.hasValidToken();
 
-      expect(service.setCurrentUser).toHaveBeenCalled();
+      expect(result).toBeFalsy();
     });
   });
 
diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.ts b/alfa-client/libs/authentication/src/lib/authentication.service.ts
index 9b094a2ba2..e6957194ff 100644
--- a/alfa-client/libs/authentication/src/lib/authentication.service.ts
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.ts
@@ -22,16 +22,20 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { Environment, ENVIRONMENT_CONFIG } from '@alfa-client/environment-shared';
+import { isNotNull } from '@alfa-client/tech-shared';
 import { Inject, Injectable } from '@angular/core';
-import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
+import { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc';
 import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
 import { UserProfileResource } from 'libs/user-profile-shared/src/lib/user-profile.model';
 import { getUserNameInitials } from 'libs/user-profile-shared/src/lib/user-profile.util';
+import { filter, Subscription } from 'rxjs';
 
 @Injectable({ providedIn: 'root' })
 export class AuthenticationService {
   currentUserResource: UserProfileResource;
 
+  private eventSubscription: Subscription;
+
   constructor(
     private oAuthService: OAuthService,
     @Inject(ENVIRONMENT_CONFIG) private envConfig: Environment,
@@ -41,18 +45,48 @@ export class AuthenticationService {
     this.oAuthService.configure(this.buildConfiguration());
     this.oAuthService.setupAutomaticSilentRefresh();
     this.oAuthService.tokenValidationHandler = new JwksValidationHandler();
+
+    const eventPromise: Promise<void> = this.buildEventPromise();
     await this.oAuthService.loadDiscoveryDocumentAndLogin();
-    this.setCurrentUser();
+    return eventPromise;
+  }
+
+  buildEventPromise(): Promise<void> {
+    return new Promise<void>((resolve, reject) => {
+      this.eventSubscription = this.oAuthService.events.pipe(filter((event: OAuthEvent) => this.shouldProceed(event))).subscribe({
+        next: () => {
+          this.setCurrentUser();
+          this.unsubscribeEvents();
+          resolve();
+        },
+        error: (error: any) => {
+          this.unsubscribeEvents();
+          reject(error);
+        },
+      });
+    });
+  }
+
+  shouldProceed(event: OAuthEvent): boolean {
+    return this.consideredAsLoginEvent(event.type) || this.consideredAsPageReloadEvent(event.type);
+  }
+
+  consideredAsLoginEvent(eventType: string): boolean {
+    return eventType === 'token_received';
+  }
+
+  consideredAsPageReloadEvent(eventType: string): boolean {
+    return eventType === 'discovery_document_loaded' && this.hasValidToken();
+  }
+
+  hasValidToken(): boolean {
+    return this.oAuthService.hasValidAccessToken() && this.oAuthService.hasValidIdToken();
   }
 
   buildConfiguration(): AuthConfig {
     return {
       issuer: this.envConfig.authServer + '/realms/' + this.envConfig.realm,
-      tokenEndpoint:
-        this.envConfig.authServer +
-        '/realms/' +
-        this.envConfig.realm +
-        '/protocol/openid-connect/token',
+      tokenEndpoint: this.envConfig.authServer + '/realms/' + this.envConfig.realm + '/protocol/openid-connect/token',
       redirectUri: window.location.origin + '/',
       clientId: this.envConfig.clientId,
       scope: 'openid profile',
@@ -71,10 +105,18 @@ export class AuthenticationService {
     this.currentUserResource = userResource;
   }
 
+  unsubscribeEvents(): void {
+    this.eventSubscription.unsubscribe();
+  }
+
   public getCurrentUserInitials(): string {
     return getUserNameInitials(this.currentUserResource);
   }
 
+  public isLoggedIn(): boolean {
+    return isNotNull(this.oAuthService.getIdentityClaims());
+  }
+
   public logout(): void {
     this.oAuthService.revokeTokenAndLogout();
   }
diff --git a/alfa-client/libs/authentication/test/authentication.ts b/alfa-client/libs/authentication/test/authentication.ts
index 3422390591..3cf143c030 100644
--- a/alfa-client/libs/authentication/test/authentication.ts
+++ b/alfa-client/libs/authentication/test/authentication.ts
@@ -21,8 +21,13 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { AuthConfig } from 'angular-oauth2-oidc';
+import { faker } from '@faker-js/faker';
+import { AuthConfig, OAuthEvent } from 'angular-oauth2-oidc';
 
 export function createAuthConfig(): AuthConfig {
   return {};
 }
+
+export function createOAuthEvent(): OAuthEvent {
+  return { type: <any>faker.lorem.word() };
+}
-- 
GitLab


From 8b4cda9cb430543759e2d62da8c0a249a04dee6b Mon Sep 17 00:00:00 2001
From: Martin <git@mail.de>
Date: Fri, 17 Jan 2025 17:43:53 +0100
Subject: [PATCH 2/5] OZG-6986 OZG-7509 adjust initial navigation/routing

---
 .../apps/admin/src/app/app.component.spec.ts  | 212 +++++++++++++++---
 .../apps/admin/src/app/app.component.ts       |  82 +++++--
 alfa-client/apps/admin/src/app/app.routes.ts  |   6 +-
 3 files changed, 251 insertions(+), 49 deletions(-)

diff --git a/alfa-client/apps/admin/src/app/app.component.spec.ts b/alfa-client/apps/admin/src/app/app.component.spec.ts
index 54c0b68df0..cb90801ee5 100644
--- a/alfa-client/apps/admin/src/app/app.component.spec.ts
+++ b/alfa-client/apps/admin/src/app/app.component.spec.ts
@@ -21,10 +21,11 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { ConfigurationLinkRel, ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared';
 import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared';
 import { BuildInfoComponent } from '@alfa-client/common';
 import { HasLinkPipe, createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared';
-import { Mock, dispatchEventFromFixture, existsAsHtmlElement, mock, notExistsAsHtmlElement } from '@alfa-client/test-utils';
+import { Mock, existsAsHtmlElement, mock, notExistsAsHtmlElement } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { ActivatedRoute, Router, RouterOutlet } from '@angular/router';
 import { AuthenticationService } from '@authentication';
@@ -36,11 +37,12 @@ import {
   OrgaUnitIconComponent,
   UsersIconComponent,
 } from '@ods/system';
+import { createConfigurationResource } from 'libs/admin/configuration-shared/test/configuration';
 import { MenuContainerComponent } from 'libs/admin/configuration/src/lib/menu-container/menu-container.component';
 import { createApiRootResource } from 'libs/api-root-shared/test/api-root';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { MockComponent, MockDirective } from 'ng-mocks';
-import { of } from 'rxjs';
+import { Subscription, of } from 'rxjs';
 import { UserProfileButtonContainerComponent } from '../common/user-profile-button-container/user-profile.button-container.component';
 import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/unavailable-page.component';
 import { AppComponent } from './app.component';
@@ -55,7 +57,6 @@ describe('AppComponent', () => {
   const usersRolesNavigationSelector: string = getDataTestIdOf('users-roles-navigation');
 
   const organisationsEinheitenNavigationSelector: string = getDataTestIdOf('organisations-einheiten-navigation');
-  const logoLink: string = getDataTestIdOf('logo-link');
   const routerOutletSelector: string = getDataTestIdOf('router-outlet');
   const menuContainer: string = getDataTestIdOf('menu-container');
 
@@ -78,8 +79,11 @@ describe('AppComponent', () => {
   };
 
   const apiRootService: Mock<ApiRootService> = mock(ApiRootService);
+  let configurationService: Mock<ConfigurationService>;
 
   beforeEach(async () => {
+    configurationService = mock(ConfigurationService);
+
     await TestBed.configureTestingModule({
       imports: [HasLinkPipe],
       declarations: [
@@ -105,6 +109,10 @@ describe('AppComponent', () => {
           provide: ApiRootService,
           useValue: apiRootService,
         },
+        {
+          provide: ConfigurationService,
+          useValue: configurationService,
+        },
         {
           provide: Router,
           useValue: router,
@@ -147,26 +155,195 @@ describe('AppComponent', () => {
     });
 
     describe('do after logged in', () => {
+      beforeEach(() => {
+        component.evaluateInitialNavigation = jest.fn();
+      });
+
       it('should call apiRootService to getApiRoot', () => {
         component.doAfterLoggedIn();
 
         expect(apiRootService.getApiRoot).toHaveBeenCalled();
       });
 
-      it('should call forwardWithoutAuthenticationParams', () => {
-        component.forwardWithoutAuthenticationParams = jest.fn();
+      it('should call evaluateInitialNavigation', () => {
+        component.evaluateInitialNavigation = jest.fn();
 
         component.doAfterLoggedIn();
 
-        expect(component.forwardWithoutAuthenticationParams).toHaveBeenCalled();
+        expect(component.evaluateInitialNavigation).toHaveBeenCalled();
+      });
+    });
+
+    describe('evaluate initial navigation', () => {
+      beforeEach(() => {
+        component.evaluateNavigationByApiRoot = jest.fn();
+      });
+
+      it('should call evaluate navigation by apiRoot', () => {
+        const apiRootResource: ApiRootResource = createApiRootResource();
+        component.apiRootStateResource$ = of(createStateResource(apiRootResource));
+
+        component.evaluateInitialNavigation();
+
+        expect(component.evaluateNavigationByApiRoot).toHaveBeenCalledWith(apiRootResource);
+      });
+
+      it('should NOT call evaluate navigation by apiRoot if resource is loading', () => {
+        component.apiRootStateResource$ = of(createEmptyStateResource<ApiRootResource>(true));
+        component.evaluateNavigationByApiRoot = jest.fn();
+
+        component.evaluateInitialNavigation();
+
+        expect(component.evaluateNavigationByApiRoot).not.toHaveBeenCalled();
+      });
+    });
+
+    describe('evaluate navigation api root', () => {
+      it('should evaluate navigation by configuration if link exists', () => {
+        component.evaluateNavigationByConfiguration = jest.fn();
+        const apiRootResource: ApiRootResource = createApiRootResource([ApiRootLinkRel.CONFIGURATION]);
+
+        component.evaluateNavigationByApiRoot(apiRootResource);
+
+        expect(component.evaluateNavigationByConfiguration).toHaveBeenCalled();
+      });
+
+      it('should do navigation by api root if link is missing', () => {
+        component.doNavigationByApiRoot = jest.fn();
+        const apiRootResource: ApiRootResource = createApiRootResource();
+
+        component.evaluateNavigationByApiRoot(apiRootResource);
+
+        expect(component.doNavigationByApiRoot).toHaveBeenCalledWith(apiRootResource);
+      });
+    });
+
+    describe('evaluate navigation by configuration', () => {
+      const configurationResource: ConfigurationResource = createConfigurationResource();
+
+      beforeEach(() => {
+        configurationService.get.mockReturnValue(of(createStateResource(configurationResource)));
+        component.doNavigationByConfiguration = jest.fn();
+      });
+
+      it('should call configuration service to get resource', () => {
+        component.evaluateNavigationByConfiguration();
+
+        expect(configurationService.get).toHaveBeenCalled();
+      });
+
+      it('should call do navigation by configuration', () => {
+        component.evaluateNavigationByConfiguration();
+
+        expect(component.doNavigationByConfiguration).toHaveBeenCalledWith(configurationResource);
+      });
+
+      it('should NOT call do navigation by configuration if resource is loading', () => {
+        configurationService.get.mockReturnValue(of(createEmptyStateResource<ConfigurationResource>(true)));
+
+        component.evaluateNavigationByConfiguration();
+
+        expect(component.doNavigationByConfiguration).not.toHaveBeenCalled();
+      });
+    });
+
+    describe('do navigation by configuration', () => {
+      beforeEach(() => {
+        component.unsubscribe = jest.fn();
+      });
+
+      it('should navigate to postfach if settings link exists', () => {
+        component.doNavigationByConfiguration(createConfigurationResource([ConfigurationLinkRel.SETTING]));
+
+        expect(router.navigate).toHaveBeenCalledWith(['/postfach']);
+      });
+
+      it('should navigate to statistik if aggregation mapping link exists', () => {
+        component.doNavigationByConfiguration(createConfigurationResource([ConfigurationLinkRel.AGGREGATION_MAPPINGS]));
+
+        expect(router.navigate).toHaveBeenCalledWith(['/statistik']);
+      });
+
+      it('should navigate to unavailable page if no link exists', () => {
+        component.doNavigationByConfiguration(createConfigurationResource());
+
+        expect(router.navigate).toHaveBeenCalledWith(['/unavailable']);
+      });
+
+      it('should call unsubscribe', () => {
+        component.doNavigationByConfiguration(createConfigurationResource());
+
+        expect(component.unsubscribe).toHaveBeenCalled();
+      });
+    });
+
+    describe('do navigation by api root', () => {
+      beforeEach(() => {
+        component.unsubscribe = jest.fn();
+      });
+
+      it('should navigate to benutzer und rollen if users link exists', () => {
+        const apiRootResource: ApiRootResource = createApiRootResource([ApiRootLinkRel.USERS]);
+
+        component.doNavigationByApiRoot(apiRootResource);
+
+        expect(router.navigate).toHaveBeenCalledWith(['/benutzer_und_rollen']);
+      });
+
+      it('should navigate to unavailable page if no link exists', () => {
+        component.doNavigationByApiRoot(createApiRootResource());
+
+        expect(router.navigate).toHaveBeenCalledWith(['/unavailable']);
+      });
+
+      it('should call unsubscribe', () => {
+        component.doNavigationByApiRoot(createApiRootResource());
+
+        expect(component.unsubscribe).toHaveBeenCalled();
       });
     });
 
-    describe('forward without authentication params', () => {
-      it('should navigate to same route without authentication params', () => {
-        component.forwardWithoutAuthenticationParams();
+    describe('unsubscribe', () => {
+      describe('apiRoot subscription', () => {
+        it('should unsubscribe if exists', () => {
+          component.apiRootSubscription = <any>mock(Subscription);
+          component.apiRootSubscription.unsubscribe = jest.fn();
 
-        expect(router.navigate).toHaveBeenCalledWith([], { queryParams: {} });
+          component.unsubscribe();
+
+          expect(component.apiRootSubscription.unsubscribe).toHaveBeenCalled();
+        });
+
+        it('should do nothing if not exists', () => {
+          component.apiRootSubscription = undefined;
+          const unsubscribeSpy: jest.SpyInstance = jest.spyOn(Subscription.prototype, 'unsubscribe');
+
+          component.unsubscribe();
+
+          expect(unsubscribeSpy).not.toHaveBeenCalled();
+          unsubscribeSpy.mockRestore();
+        });
+      });
+
+      describe('configuration subscription', () => {
+        it('should unsubscribe if exists', () => {
+          component.configurationSubscription = <any>mock(Subscription);
+          component.configurationSubscription.unsubscribe = jest.fn();
+
+          component.unsubscribe();
+
+          expect(component.configurationSubscription.unsubscribe).toHaveBeenCalled();
+        });
+
+        it('should do nothing if not exists', () => {
+          component.apiRootSubscription = undefined;
+          const unsubscribeSpy: jest.SpyInstance = jest.spyOn(Subscription.prototype, 'unsubscribe');
+
+          component.unsubscribe();
+
+          expect(unsubscribeSpy).not.toHaveBeenCalled();
+          unsubscribeSpy.mockRestore();
+        });
       });
     });
   });
@@ -190,21 +367,6 @@ describe('AppComponent', () => {
       });
     });
 
-    describe('administration logo', () => {
-      const apiResource: ApiRootResource = createApiRootResource();
-
-      beforeEach(() => {
-        component.apiRootStateResource$ = of(createStateResource(apiResource));
-        fixture.detectChanges();
-      });
-
-      it('should navigate to start page on click', () => {
-        dispatchEventFromFixture(fixture, logoLink, 'click');
-
-        expect(router.navigate).toHaveBeenCalledWith([], { queryParams: {} });
-      });
-    });
-
     describe('navigation', () => {
       describe('user and roles', () => {
         it('should show if users link is present', () => {
diff --git a/alfa-client/apps/admin/src/app/app.component.ts b/alfa-client/apps/admin/src/app/app.component.ts
index 77e7d9b5bb..979c8024a5 100644
--- a/alfa-client/apps/admin/src/app/app.component.ts
+++ b/alfa-client/apps/admin/src/app/app.component.ts
@@ -22,13 +22,16 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { MenuContainerComponent } from '@admin-client/configuration';
+import { ConfigurationLinkRel, ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared';
+import { ROUTES } from '@admin-client/shared';
 import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared';
 import { BuildInfoComponent } from '@alfa-client/common';
-import { StateResource, TechSharedModule } from '@alfa-client/tech-shared';
+import { isLoaded, isNotUndefined, mapToResource, StateResource, TechSharedModule } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
-import { Component, OnInit } from '@angular/core';
-import { ActivatedRoute, Params, Router, RouterLink, RouterOutlet } from '@angular/router';
+import { Component, inject, OnInit } from '@angular/core';
+import { Router, RouterLink, RouterOutlet } from '@angular/router';
 import { AuthenticationService } from '@authentication';
+import { hasLink } from '@ngxp/rest';
 import {
   AdminLogoIconComponent,
   NavbarComponent,
@@ -36,7 +39,7 @@ import {
   OrgaUnitIconComponent,
   UsersIconComponent,
 } from '@ods/system';
-import { Observable } from 'rxjs';
+import { filter, Observable, Subscription } from 'rxjs';
 import { UserProfileButtonContainerComponent } from '../common/user-profile-button-container/user-profile.button-container.component';
 import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/unavailable-page.component';
 
@@ -62,18 +65,19 @@ import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/
   ],
 })
 export class AppComponent implements OnInit {
-  readonly title: string = 'admin';
+  readonly title = 'admin';
+
+  private readonly authenticationService: AuthenticationService = inject(AuthenticationService);
+  private readonly apiRootService: ApiRootService = inject(ApiRootService);
+  private readonly router: Router = inject(Router);
+  private readonly configurationService: ConfigurationService = inject(ConfigurationService);
 
   public apiRootStateResource$: Observable<StateResource<ApiRootResource>>;
 
-  public readonly apiRootLinkRel = ApiRootLinkRel;
+  apiRootSubscription: Subscription;
+  configurationSubscription: Subscription;
 
-  constructor(
-    public authenticationService: AuthenticationService,
-    private apiRootService: ApiRootService,
-    private router: Router,
-    private route: ActivatedRoute,
-  ) {}
+  public readonly apiRootLinkRel = ApiRootLinkRel;
 
   ngOnInit(): void {
     this.authenticationService.login().then(() => this.doAfterLoggedIn());
@@ -81,16 +85,56 @@ export class AppComponent implements OnInit {
 
   doAfterLoggedIn(): void {
     this.apiRootStateResource$ = this.apiRootService.getApiRoot();
-    this.forwardWithoutAuthenticationParams();
+    this.evaluateInitialNavigation();
+  }
+
+  evaluateInitialNavigation(): void {
+    this.apiRootSubscription = this.apiRootStateResource$
+      .pipe(filter(isLoaded), mapToResource<ApiRootResource>())
+      .subscribe((apiRootResource: ApiRootResource) => this.evaluateNavigationByApiRoot(apiRootResource));
+  }
+
+  evaluateNavigationByApiRoot(apiRootResource: ApiRootResource): void {
+    if (hasLink(apiRootResource, ApiRootLinkRel.CONFIGURATION)) {
+      this.evaluateNavigationByConfiguration();
+    } else {
+      this.doNavigationByApiRoot(apiRootResource);
+    }
+  }
+
+  evaluateNavigationByConfiguration(): void {
+    this.configurationSubscription = this.configurationService
+      .get()
+      .pipe(filter(isLoaded), mapToResource<ApiRootResource>())
+      .subscribe((configurationResource: ConfigurationResource) => this.doNavigationByConfiguration(configurationResource));
+  }
+
+  doNavigationByConfiguration(configurationResource: ConfigurationResource): void {
+    if (hasLink(configurationResource, ConfigurationLinkRel.SETTING)) {
+      this.doInitialNavigation(ROUTES.POSTFACH);
+    } else if (hasLink(configurationResource, ConfigurationLinkRel.AGGREGATION_MAPPINGS)) {
+      this.doInitialNavigation(ROUTES.STATISTIK);
+    } else {
+      this.doInitialNavigation(ROUTES.UNAVAILABLE);
+    }
+    this.unsubscribe();
+  }
+
+  doNavigationByApiRoot(apiRootResource: ApiRootResource): void {
+    if (hasLink(apiRootResource, ApiRootLinkRel.USERS)) {
+      this.doInitialNavigation(ROUTES.BENUTZER_UND_ROLLEN);
+    } else {
+      this.doInitialNavigation(ROUTES.UNAVAILABLE);
+    }
+    this.unsubscribe();
   }
 
-  forwardWithoutAuthenticationParams(): void {
-    const queryParams: Params = this.getQueryParamsWithoutAuthentication();
-    this.router.navigate([], { queryParams });
+  private doInitialNavigation(routePath: string): void {
+    this.router.navigate(['/' + routePath]);
   }
 
-  private getQueryParamsWithoutAuthentication(): Params {
-    const { iss, state, session_state, code, ...queryParams } = this.route.snapshot.queryParams;
-    return queryParams;
+  unsubscribe(): void {
+    if (isNotUndefined(this.apiRootSubscription)) this.apiRootSubscription.unsubscribe();
+    if (isNotUndefined(this.configurationSubscription)) this.configurationSubscription.unsubscribe();
   }
 }
diff --git a/alfa-client/apps/admin/src/app/app.routes.ts b/alfa-client/apps/admin/src/app/app.routes.ts
index e26615b6c1..a7ed852a61 100644
--- a/alfa-client/apps/admin/src/app/app.routes.ts
+++ b/alfa-client/apps/admin/src/app/app.routes.ts
@@ -37,12 +37,8 @@ import { apiRootGuard, configurationGuard } from './app.guard';
 export interface GuardData {
   linkRelName: string;
 }
+
 export const appRoutes: Route[] = [
-  {
-    path: '',
-    redirectTo: ROUTES.POSTFACH,
-    pathMatch: 'full',
-  },
   {
     path: ROUTES.POSTFACH,
     component: PostfachPageComponent,
-- 
GitLab


From 78b06a2e49bcbf250c030473baec556f36d54bf4 Mon Sep 17 00:00:00 2001
From: Martin <git@mail.de>
Date: Fri, 17 Jan 2025 17:46:39 +0100
Subject: [PATCH 3/5] OZG-6986 OZG-7509 cleanup

---
 .../libs/authentication/src/lib/authentication.service.ts    | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.ts b/alfa-client/libs/authentication/src/lib/authentication.service.ts
index e6957194ff..7dcfc4741a 100644
--- a/alfa-client/libs/authentication/src/lib/authentication.service.ts
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.ts
@@ -22,7 +22,6 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { Environment, ENVIRONMENT_CONFIG } from '@alfa-client/environment-shared';
-import { isNotNull } from '@alfa-client/tech-shared';
 import { Inject, Injectable } from '@angular/core';
 import { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc';
 import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
@@ -113,10 +112,6 @@ export class AuthenticationService {
     return getUserNameInitials(this.currentUserResource);
   }
 
-  public isLoggedIn(): boolean {
-    return isNotNull(this.oAuthService.getIdentityClaims());
-  }
-
   public logout(): void {
     this.oAuthService.revokeTokenAndLogout();
   }
-- 
GitLab


From 055eaa6ffe657a490e2be65587c1a6bd4e051d7f Mon Sep 17 00:00:00 2001
From: Martin <git@mail.de>
Date: Mon, 20 Jan 2025 11:08:23 +0100
Subject: [PATCH 4/5] OZG-6986 impl MR comments

---
 .../apps/admin/src/app/app.component.spec.ts  | 34 +++++++++----------
 .../apps/admin/src/app/app.component.ts       | 30 ++++++++--------
 .../src/lib/authentication.service.spec.ts    | 18 +++++-----
 .../src/lib/authentication.service.ts         | 12 ++++---
 4 files changed, 49 insertions(+), 45 deletions(-)

diff --git a/alfa-client/apps/admin/src/app/app.component.spec.ts b/alfa-client/apps/admin/src/app/app.component.spec.ts
index cb90801ee5..86fda2c791 100644
--- a/alfa-client/apps/admin/src/app/app.component.spec.ts
+++ b/alfa-client/apps/admin/src/app/app.component.spec.ts
@@ -208,13 +208,13 @@ describe('AppComponent', () => {
         expect(component.evaluateNavigationByConfiguration).toHaveBeenCalled();
       });
 
-      it('should do navigation by api root if link is missing', () => {
-        component.doNavigationByApiRoot = jest.fn();
+      it('should navigate by api root if link is missing', () => {
+        component.navigateByApiRoot = jest.fn();
         const apiRootResource: ApiRootResource = createApiRootResource();
 
         component.evaluateNavigationByApiRoot(apiRootResource);
 
-        expect(component.doNavigationByApiRoot).toHaveBeenCalledWith(apiRootResource);
+        expect(component.navigateByApiRoot).toHaveBeenCalledWith(apiRootResource);
       });
     });
 
@@ -223,7 +223,7 @@ describe('AppComponent', () => {
 
       beforeEach(() => {
         configurationService.get.mockReturnValue(of(createStateResource(configurationResource)));
-        component.doNavigationByConfiguration = jest.fn();
+        component.navigateByConfiguration = jest.fn();
       });
 
       it('should call configuration service to get resource', () => {
@@ -232,52 +232,52 @@ describe('AppComponent', () => {
         expect(configurationService.get).toHaveBeenCalled();
       });
 
-      it('should call do navigation by configuration', () => {
+      it('should call navigate by configuration', () => {
         component.evaluateNavigationByConfiguration();
 
-        expect(component.doNavigationByConfiguration).toHaveBeenCalledWith(configurationResource);
+        expect(component.navigateByConfiguration).toHaveBeenCalledWith(configurationResource);
       });
 
-      it('should NOT call do navigation by configuration if resource is loading', () => {
+      it('should NOT call navigate by configuration if resource is loading', () => {
         configurationService.get.mockReturnValue(of(createEmptyStateResource<ConfigurationResource>(true)));
 
         component.evaluateNavigationByConfiguration();
 
-        expect(component.doNavigationByConfiguration).not.toHaveBeenCalled();
+        expect(component.navigateByConfiguration).not.toHaveBeenCalled();
       });
     });
 
-    describe('do navigation by configuration', () => {
+    describe('navigate by configuration', () => {
       beforeEach(() => {
         component.unsubscribe = jest.fn();
       });
 
       it('should navigate to postfach if settings link exists', () => {
-        component.doNavigationByConfiguration(createConfigurationResource([ConfigurationLinkRel.SETTING]));
+        component.navigateByConfiguration(createConfigurationResource([ConfigurationLinkRel.SETTING]));
 
         expect(router.navigate).toHaveBeenCalledWith(['/postfach']);
       });
 
       it('should navigate to statistik if aggregation mapping link exists', () => {
-        component.doNavigationByConfiguration(createConfigurationResource([ConfigurationLinkRel.AGGREGATION_MAPPINGS]));
+        component.navigateByConfiguration(createConfigurationResource([ConfigurationLinkRel.AGGREGATION_MAPPINGS]));
 
         expect(router.navigate).toHaveBeenCalledWith(['/statistik']);
       });
 
       it('should navigate to unavailable page if no link exists', () => {
-        component.doNavigationByConfiguration(createConfigurationResource());
+        component.navigateByConfiguration(createConfigurationResource());
 
         expect(router.navigate).toHaveBeenCalledWith(['/unavailable']);
       });
 
       it('should call unsubscribe', () => {
-        component.doNavigationByConfiguration(createConfigurationResource());
+        component.navigateByConfiguration(createConfigurationResource());
 
         expect(component.unsubscribe).toHaveBeenCalled();
       });
     });
 
-    describe('do navigation by api root', () => {
+    describe('navigate by api root', () => {
       beforeEach(() => {
         component.unsubscribe = jest.fn();
       });
@@ -285,19 +285,19 @@ describe('AppComponent', () => {
       it('should navigate to benutzer und rollen if users link exists', () => {
         const apiRootResource: ApiRootResource = createApiRootResource([ApiRootLinkRel.USERS]);
 
-        component.doNavigationByApiRoot(apiRootResource);
+        component.navigateByApiRoot(apiRootResource);
 
         expect(router.navigate).toHaveBeenCalledWith(['/benutzer_und_rollen']);
       });
 
       it('should navigate to unavailable page if no link exists', () => {
-        component.doNavigationByApiRoot(createApiRootResource());
+        component.navigateByApiRoot(createApiRootResource());
 
         expect(router.navigate).toHaveBeenCalledWith(['/unavailable']);
       });
 
       it('should call unsubscribe', () => {
-        component.doNavigationByApiRoot(createApiRootResource());
+        component.navigateByApiRoot(createApiRootResource());
 
         expect(component.unsubscribe).toHaveBeenCalled();
       });
diff --git a/alfa-client/apps/admin/src/app/app.component.ts b/alfa-client/apps/admin/src/app/app.component.ts
index 979c8024a5..c9d3c4f536 100644
--- a/alfa-client/apps/admin/src/app/app.component.ts
+++ b/alfa-client/apps/admin/src/app/app.component.ts
@@ -65,12 +65,12 @@ import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/
   ],
 })
 export class AppComponent implements OnInit {
-  readonly title = 'admin';
+  readonly title: string = 'admin';
 
-  private readonly authenticationService: AuthenticationService = inject(AuthenticationService);
-  private readonly apiRootService: ApiRootService = inject(ApiRootService);
-  private readonly router: Router = inject(Router);
-  private readonly configurationService: ConfigurationService = inject(ConfigurationService);
+  private readonly authenticationService = inject(AuthenticationService);
+  private readonly apiRootService = inject(ApiRootService);
+  private readonly router = inject(Router);
+  private readonly configurationService = inject(ConfigurationService);
 
   public apiRootStateResource$: Observable<StateResource<ApiRootResource>>;
 
@@ -98,7 +98,7 @@ export class AppComponent implements OnInit {
     if (hasLink(apiRootResource, ApiRootLinkRel.CONFIGURATION)) {
       this.evaluateNavigationByConfiguration();
     } else {
-      this.doNavigationByApiRoot(apiRootResource);
+      this.navigateByApiRoot(apiRootResource);
     }
   }
 
@@ -106,30 +106,30 @@ export class AppComponent implements OnInit {
     this.configurationSubscription = this.configurationService
       .get()
       .pipe(filter(isLoaded), mapToResource<ApiRootResource>())
-      .subscribe((configurationResource: ConfigurationResource) => this.doNavigationByConfiguration(configurationResource));
+      .subscribe((configurationResource: ConfigurationResource) => this.navigateByConfiguration(configurationResource));
   }
 
-  doNavigationByConfiguration(configurationResource: ConfigurationResource): void {
+  navigateByConfiguration(configurationResource: ConfigurationResource): void {
     if (hasLink(configurationResource, ConfigurationLinkRel.SETTING)) {
-      this.doInitialNavigation(ROUTES.POSTFACH);
+      this.navigate(ROUTES.POSTFACH);
     } else if (hasLink(configurationResource, ConfigurationLinkRel.AGGREGATION_MAPPINGS)) {
-      this.doInitialNavigation(ROUTES.STATISTIK);
+      this.navigate(ROUTES.STATISTIK);
     } else {
-      this.doInitialNavigation(ROUTES.UNAVAILABLE);
+      this.navigate(ROUTES.UNAVAILABLE);
     }
     this.unsubscribe();
   }
 
-  doNavigationByApiRoot(apiRootResource: ApiRootResource): void {
+  navigateByApiRoot(apiRootResource: ApiRootResource): void {
     if (hasLink(apiRootResource, ApiRootLinkRel.USERS)) {
-      this.doInitialNavigation(ROUTES.BENUTZER_UND_ROLLEN);
+      this.navigate(ROUTES.BENUTZER_UND_ROLLEN);
     } else {
-      this.doInitialNavigation(ROUTES.UNAVAILABLE);
+      this.navigate(ROUTES.UNAVAILABLE);
     }
     this.unsubscribe();
   }
 
-  private doInitialNavigation(routePath: string): void {
+  private navigate(routePath: string): void {
     this.router.navigate(['/' + routePath]);
   }
 
diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
index 1ef750f989..14b3984a18 100644
--- a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
@@ -109,16 +109,16 @@ describe('AuthenticationService', () => {
     const event: OAuthEvent = createOAuthEvent();
 
     beforeEach(() => {
-      service.shouldProceed = jest.fn().mockReturnValue(true);
+      service.shouldProceedByType = jest.fn().mockReturnValue(true);
       service.setCurrentUser = jest.fn();
       service.unsubscribeEvents = jest.fn();
     });
 
-    it('should call shouldProceed on event trigger', () => {
+    it('should call shouldProceedByType on event trigger', () => {
       service.buildEventPromise();
       eventsSubject.next(event);
 
-      expect(service.shouldProceed).toHaveBeenCalledWith(event);
+      expect(service.shouldProceedByType).toHaveBeenCalledWith(event);
     });
 
     describe('on next', () => {
@@ -165,13 +165,13 @@ describe('AuthenticationService', () => {
     });
   });
 
-  describe('should proceed', () => {
+  describe('should proceed by type', () => {
     const event: OAuthEvent = createOAuthEvent();
 
     it('should call considered as login event', () => {
       service.consideredAsLoginEvent = jest.fn();
 
-      service.shouldProceed(event);
+      service.shouldProceedByType(event);
 
       expect(service.consideredAsLoginEvent).toHaveBeenCalledWith(event.type);
     });
@@ -179,7 +179,7 @@ describe('AuthenticationService', () => {
     it('should return true on login event', () => {
       service.consideredAsLoginEvent = jest.fn().mockReturnValue(true);
 
-      const proceed: boolean = service.shouldProceed(event);
+      const proceed: boolean = service.shouldProceedByType(event);
 
       expect(proceed).toBeTruthy();
     });
@@ -188,7 +188,7 @@ describe('AuthenticationService', () => {
       service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
       service.consideredAsPageReloadEvent = jest.fn();
 
-      service.shouldProceed(event);
+      service.shouldProceedByType(event);
 
       expect(service.consideredAsPageReloadEvent).toHaveBeenCalledWith(event.type);
     });
@@ -197,7 +197,7 @@ describe('AuthenticationService', () => {
       service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
       service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(true);
 
-      const proceed: boolean = service.shouldProceed(event);
+      const proceed: boolean = service.shouldProceedByType(event);
 
       expect(proceed).toBeTruthy();
     });
@@ -206,7 +206,7 @@ describe('AuthenticationService', () => {
       service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
       service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(false);
 
-      const proceed: boolean = service.shouldProceed(event);
+      const proceed: boolean = service.shouldProceedByType(event);
 
       expect(proceed).toBeFalsy();
     });
diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.ts b/alfa-client/libs/authentication/src/lib/authentication.service.ts
index 7dcfc4741a..b22baa5b45 100644
--- a/alfa-client/libs/authentication/src/lib/authentication.service.ts
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.ts
@@ -51,8 +51,13 @@ export class AuthenticationService {
   }
 
   buildEventPromise(): Promise<void> {
-    return new Promise<void>((resolve, reject) => {
-      this.eventSubscription = this.oAuthService.events.pipe(filter((event: OAuthEvent) => this.shouldProceed(event))).subscribe({
+    return new Promise<void>((resolve, reject) => this.handleOAuthEventsForPromise(resolve, reject));
+  }
+
+  private handleOAuthEventsForPromise(resolve: (value: void | PromiseLike<void>) => void, reject: (reason?: any) => void): void {
+    this.eventSubscription = this.oAuthService.events
+      .pipe(filter((event: OAuthEvent) => this.shouldProceedByType(event)))
+      .subscribe({
         next: () => {
           this.setCurrentUser();
           this.unsubscribeEvents();
@@ -63,10 +68,9 @@ export class AuthenticationService {
           reject(error);
         },
       });
-    });
   }
 
-  shouldProceed(event: OAuthEvent): boolean {
+  shouldProceedByType(event: OAuthEvent): boolean {
     return this.consideredAsLoginEvent(event.type) || this.consideredAsPageReloadEvent(event.type);
   }
 
-- 
GitLab


From 96410d88d80d0e2ec83cec9aeee13d460c94186b Mon Sep 17 00:00:00 2001
From: Martin <git@mail.de>
Date: Mon, 20 Jan 2025 12:25:02 +0100
Subject: [PATCH 5/5] OZG-6986 rename Functions

---
 .../src/lib/authentication.service.spec.ts    | 42 +++++++++----------
 .../src/lib/authentication.service.ts         | 12 +++---
 2 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
index 14b3984a18..486415f425 100644
--- a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
@@ -55,7 +55,7 @@ describe('AuthenticationService', () => {
 
   describe('login', () => {
     beforeEach(() => {
-      service.buildEventPromise = jest.fn();
+      service.buildAuthEventPromise = jest.fn();
     });
 
     it('should configure service with authConfig', async () => {
@@ -81,12 +81,12 @@ describe('AuthenticationService', () => {
       expect(oAuthService.tokenValidationHandler).not.toBeNull();
     });
 
-    it('should build event promise', async () => {
-      service.buildEventPromise = jest.fn().mockResolvedValue(() => Promise.resolve());
+    it('should build auth event promise', async () => {
+      service.buildAuthEventPromise = jest.fn().mockResolvedValue(() => Promise.resolve());
 
       await service.login();
 
-      expect(service.buildEventPromise).toHaveBeenCalled();
+      expect(service.buildAuthEventPromise).toHaveBeenCalled();
     });
 
     it('should load discovery document and login', () => {
@@ -97,7 +97,7 @@ describe('AuthenticationService', () => {
 
     it('should return eventPromise', async () => {
       const promise: Promise<void> = Promise.resolve();
-      service.buildEventPromise = jest.fn().mockResolvedValue(promise);
+      service.buildAuthEventPromise = jest.fn().mockResolvedValue(promise);
 
       const returnPromise: Promise<void> = service.login();
 
@@ -105,39 +105,39 @@ describe('AuthenticationService', () => {
     });
   });
 
-  describe('build event promise', () => {
+  describe('build auth event promise', () => {
     const event: OAuthEvent = createOAuthEvent();
 
     beforeEach(() => {
-      service.shouldProceedByType = jest.fn().mockReturnValue(true);
+      service.shouldProceedByAuthEvent = jest.fn().mockReturnValue(true);
       service.setCurrentUser = jest.fn();
       service.unsubscribeEvents = jest.fn();
     });
 
-    it('should call shouldProceedByType on event trigger', () => {
-      service.buildEventPromise();
+    it('should call shouldProceedByAuthEvent on event trigger', () => {
+      service.buildAuthEventPromise();
       eventsSubject.next(event);
 
-      expect(service.shouldProceedByType).toHaveBeenCalledWith(event);
+      expect(service.shouldProceedByAuthEvent).toHaveBeenCalledWith(event);
     });
 
     describe('on next', () => {
       it('should set current user', () => {
-        service.buildEventPromise();
+        service.buildAuthEventPromise();
         eventsSubject.next(event);
 
         expect(service.setCurrentUser).toHaveBeenCalled();
       });
 
       it('should unsubscribe event', () => {
-        service.buildEventPromise();
+        service.buildAuthEventPromise();
         eventsSubject.next(event);
 
         expect(service.unsubscribeEvents).toHaveBeenCalled();
       });
 
       it('should resolved promise with a valid event', async () => {
-        const promise: Promise<void> = service.buildEventPromise();
+        const promise: Promise<void> = service.buildAuthEventPromise();
         eventsSubject.next(event);
 
         await expect(promise).resolves.toBeUndefined();
@@ -149,14 +149,14 @@ describe('AuthenticationService', () => {
       const error: Error = new Error(errorMessage);
 
       it('should unsubscribe event', () => {
-        service.buildEventPromise();
+        service.buildAuthEventPromise();
         eventsSubject.error(error);
 
         expect(service.unsubscribeEvents).toHaveBeenCalled();
       });
 
       it('should reject the promise with an error', async () => {
-        const promise: Promise<void> = service.buildEventPromise();
+        const promise: Promise<void> = service.buildAuthEventPromise();
 
         eventsSubject.error(error);
 
@@ -165,13 +165,13 @@ describe('AuthenticationService', () => {
     });
   });
 
-  describe('should proceed by type', () => {
+  describe('should proceed by auth event', () => {
     const event: OAuthEvent = createOAuthEvent();
 
     it('should call considered as login event', () => {
       service.consideredAsLoginEvent = jest.fn();
 
-      service.shouldProceedByType(event);
+      service.shouldProceedByAuthEvent(event);
 
       expect(service.consideredAsLoginEvent).toHaveBeenCalledWith(event.type);
     });
@@ -179,7 +179,7 @@ describe('AuthenticationService', () => {
     it('should return true on login event', () => {
       service.consideredAsLoginEvent = jest.fn().mockReturnValue(true);
 
-      const proceed: boolean = service.shouldProceedByType(event);
+      const proceed: boolean = service.shouldProceedByAuthEvent(event);
 
       expect(proceed).toBeTruthy();
     });
@@ -188,7 +188,7 @@ describe('AuthenticationService', () => {
       service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
       service.consideredAsPageReloadEvent = jest.fn();
 
-      service.shouldProceedByType(event);
+      service.shouldProceedByAuthEvent(event);
 
       expect(service.consideredAsPageReloadEvent).toHaveBeenCalledWith(event.type);
     });
@@ -197,7 +197,7 @@ describe('AuthenticationService', () => {
       service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
       service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(true);
 
-      const proceed: boolean = service.shouldProceedByType(event);
+      const proceed: boolean = service.shouldProceedByAuthEvent(event);
 
       expect(proceed).toBeTruthy();
     });
@@ -206,7 +206,7 @@ describe('AuthenticationService', () => {
       service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
       service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(false);
 
-      const proceed: boolean = service.shouldProceedByType(event);
+      const proceed: boolean = service.shouldProceedByAuthEvent(event);
 
       expect(proceed).toBeFalsy();
     });
diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.ts b/alfa-client/libs/authentication/src/lib/authentication.service.ts
index b22baa5b45..e350dcafe7 100644
--- a/alfa-client/libs/authentication/src/lib/authentication.service.ts
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.ts
@@ -45,18 +45,18 @@ export class AuthenticationService {
     this.oAuthService.setupAutomaticSilentRefresh();
     this.oAuthService.tokenValidationHandler = new JwksValidationHandler();
 
-    const eventPromise: Promise<void> = this.buildEventPromise();
+    const eventPromise: Promise<void> = this.buildAuthEventPromise();
     await this.oAuthService.loadDiscoveryDocumentAndLogin();
     return eventPromise;
   }
 
-  buildEventPromise(): Promise<void> {
-    return new Promise<void>((resolve, reject) => this.handleOAuthEventsForPromise(resolve, reject));
+  buildAuthEventPromise(): Promise<void> {
+    return new Promise<void>((resolve, reject) => this.handleAuthEventsForPromise(resolve, reject));
   }
 
-  private handleOAuthEventsForPromise(resolve: (value: void | PromiseLike<void>) => void, reject: (reason?: any) => void): void {
+  private handleAuthEventsForPromise(resolve: (value: void | PromiseLike<void>) => void, reject: (reason?: any) => void): void {
     this.eventSubscription = this.oAuthService.events
-      .pipe(filter((event: OAuthEvent) => this.shouldProceedByType(event)))
+      .pipe(filter((event: OAuthEvent) => this.shouldProceedByAuthEvent(event)))
       .subscribe({
         next: () => {
           this.setCurrentUser();
@@ -70,7 +70,7 @@ export class AuthenticationService {
       });
   }
 
-  shouldProceedByType(event: OAuthEvent): boolean {
+  shouldProceedByAuthEvent(event: OAuthEvent): boolean {
     return this.consideredAsLoginEvent(event.type) || this.consideredAsPageReloadEvent(event.type);
   }
 
-- 
GitLab