diff --git a/alfa-client/.gitignore b/alfa-client/.gitignore
index 6116ea3d904921685f791527ee0ec33f12136fa8..82940fc64c73f76b3c97bc2e4f5a4d69a2aef4cc 100644
--- a/alfa-client/.gitignore
+++ b/alfa-client/.gitignore
@@ -49,3 +49,5 @@ testem.log
 .DS_Store
 Thumbs.db
 
+
+.angular
diff --git a/alfa-client/apps/admin/src/app/app.component.html b/alfa-client/apps/admin/src/app/app.component.html
index f9f6573f38f14c261b0d6c431ad1fb0a1cd327c5..d75f9414d1097d6d62358170a21086cb916e3412 100644
--- a/alfa-client/apps/admin/src/app/app.component.html
+++ b/alfa-client/apps/admin/src/app/app.component.html
@@ -1,4 +1,4 @@
-<ng-container *ngIf="(apiRoot$ | async)?.resource as apiRoot">
+<ng-container *ngIf="(apiRootStateResource$ | async)?.resource as apiRoot">
   <header class="flex items-center justify-between bg-white p-6" data-test-id="admin-header">
     <div class="text-ozgblue font-extrabold">OZG-Cloud Administration</div>
     <div>
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 0fd3f5bb0cc54356d34ab02ddcff92a344d730bc..52e41ae571ae5ef0fc7a8c025e58bfe1a815abfb 100644
--- a/alfa-client/apps/admin/src/app/app.component.spec.ts
+++ b/alfa-client/apps/admin/src/app/app.component.spec.ts
@@ -3,7 +3,7 @@ import { RouterTestingModule } from '@angular/router/testing';
 import { AppComponent } from './app.component';
 import { AuthService } from '../common/auth/auth.service';
 import { Mock, mock, existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils';
-import { ApiRootService } from '@alfa-client/api-root-shared';
+import { ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared';
 import { of } from 'rxjs';
@@ -11,6 +11,7 @@ import { createApiRootResource } from 'libs/api-root-shared/test/api-root';
 import { MockComponent } from 'ng-mocks';
 import { UserProfileButtonContainerComponent } from '../common/user-profile-button-container/user-profile.button-container.component';
 import { PostfachNavigationItemComponent } from '../pages/postfach/postfach-navigation-item/postfach-navigation-item.component';
+import { Router } from '@angular/router';
 
 describe('AppComponent', () => {
   let component: AppComponent;
@@ -21,7 +22,12 @@ describe('AppComponent', () => {
   const userProfileButton: string = getDataTestIdOf('user-profile-button');
   const postfachNavigationItem: string = getDataTestIdOf('postfach-navigation-item');
 
-  const authService: Mock<AuthService> = mock(AuthService);
+  const authService: Mock<AuthService> = {
+    ...mock(AuthService),
+    login: jest.fn().mockResolvedValue(Promise.resolve()),
+  };
+
+  const router: Mock<Router> = mock(Router);
   const apiRootService: Mock<ApiRootService> = mock(ApiRootService);
 
   beforeEach(async () => {
@@ -41,6 +47,10 @@ describe('AppComponent', () => {
           provide: ApiRootService,
           useValue: apiRootService,
         },
+        {
+          provide: Router,
+          useValue: router,
+        },
       ],
     }).compileComponents();
   });
@@ -65,10 +75,10 @@ describe('AppComponent', () => {
     });
 
     it('should call doAfterLoggedIn', async () => {
-      authService.login.mockImplementation(() => Promise.resolve());
       component.doAfterLoggedIn = jest.fn();
 
-      await component.ngOnInit();
+      component.ngOnInit();
+      await fixture.whenStable();
 
       expect(component.doAfterLoggedIn).toHaveBeenCalled();
     });
@@ -79,18 +89,24 @@ describe('AppComponent', () => {
 
         expect(apiRootService.getApiRoot).toHaveBeenCalled();
       });
+
+      it('should navigate to default route', () => {
+        component.doAfterLoggedIn();
+
+        expect(router.navigate).toHaveBeenCalledWith(['/']);
+      });
     });
   });
 
   it('show not show header if apiRoot is not loaded', () => {
-    component.apiRoot$ = of(createEmptyStateResource());
+    component.apiRootStateResource$ = of(createEmptyStateResource<ApiRootResource>());
 
     notExistsAsHtmlElement(fixture, adminHeader);
   });
 
   describe('user profile button', () => {
     beforeEach(() => {
-      component.apiRoot$ = of(createStateResource(createApiRootResource()));
+      component.apiRootStateResource$ = of(createStateResource(createApiRootResource()));
     });
 
     it('should show if apiRoot exists', () => {
@@ -102,7 +118,7 @@ describe('AppComponent', () => {
 
   describe('navigation', () => {
     beforeEach(() => {
-      component.apiRoot$ = of(createStateResource(createApiRootResource()));
+      component.apiRootStateResource$ = of(createStateResource(createApiRootResource()));
     });
     it('should have postfach item', () => {
       fixture.detectChanges();
@@ -113,7 +129,7 @@ describe('AppComponent', () => {
 
   describe('build version', () => {
     beforeEach(() => {
-      component.apiRoot$ = of(createStateResource(createApiRootResource()));
+      component.apiRootStateResource$ = of(createStateResource(createApiRootResource()));
     });
 
     it('should show after apiRoot loaded', () => {
diff --git a/alfa-client/apps/admin/src/app/app.component.ts b/alfa-client/apps/admin/src/app/app.component.ts
index 2e3c2a3e66b5ec5da01f6ff99f389c19b4b20f6d..198bc3207d5b1a4e5242d3126e636c254dde891c 100644
--- a/alfa-client/apps/admin/src/app/app.component.ts
+++ b/alfa-client/apps/admin/src/app/app.component.ts
@@ -1,7 +1,9 @@
-import { ApiRootService } from '@alfa-client/api-root-shared';
+import { ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared';
 import { Component, OnInit } from '@angular/core';
 import { Observable } from 'rxjs';
-import { AuthService } from '../common/auth/auth.service';
+import { StateResource } from '@alfa-client/tech-shared';
+import { Router } from '@angular/router';
+import { AuthenticationService } from 'libs/authentication/src/lib/authentication.service';
 
 @Component({
   selector: 'app-root',
@@ -11,18 +13,20 @@ import { AuthService } from '../common/auth/auth.service';
 export class AppComponent implements OnInit {
   readonly title = 'admin';
 
-  public apiRoot$: Observable<any>;
+  public apiRootStateResource$: Observable<StateResource<ApiRootResource>>;
 
   constructor(
-    public authService: AuthService,
+    public authenticationService: AuthenticationService,
     private apiRootService: ApiRootService,
+    private router: Router,
   ) {}
 
-  public async ngOnInit(): Promise<void> {
-    await this.authService.login().then(() => this.doAfterLoggedIn());
+  ngOnInit(): void {
+    this.authenticationService.login().then(() => this.doAfterLoggedIn());
   }
 
   doAfterLoggedIn(): void {
-    this.apiRoot$ = this.apiRootService.getApiRoot();
+    this.apiRootStateResource$ = this.apiRootService.getApiRoot();
+    this.router.navigate(['/']);
   }
 }
diff --git a/alfa-client/apps/admin/src/app/app.config.ts b/alfa-client/apps/admin/src/app/app.config.ts
deleted file mode 100644
index a6c4c188b85cc5b17d9716af420e62e1b2801d6f..0000000000000000000000000000000000000000
--- a/alfa-client/apps/admin/src/app/app.config.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Environment } from '@alfa-client/environment-shared';
-import { KeycloakService } from 'keycloak-angular';
-
-export function initializeKeycloak(keycloak: KeycloakService, envConfig: Environment) {
-  return () =>
-    keycloak.init({
-      config: {
-        url: envConfig.authServer,
-        realm: envConfig.realm,
-        clientId: envConfig.clientId,
-      },
-      initOptions: {
-        adapter: 'default',
-        checkLoginIframe: false,
-        enableLogging: true,
-        scope: 'offline_access',
-        onLoad: 'login-required',
-        silentCheckSsoRedirectUri: window.location.origin + '/assets/silent-check-sso.html',
-        silentCheckSsoFallback: true,
-      },
-      updateMinValidity: 1,
-      bearerExcludedUrls: ['/assets', '/clients/public'],
-    });
-}
diff --git a/alfa-client/apps/admin/src/app/app.module.ts b/alfa-client/apps/admin/src/app/app.module.ts
index e13deaf980ec4811058fd72666bd6a47659f2c47..9245ba29623a0ce3954336f25e74ed5319269dcf 100644
--- a/alfa-client/apps/admin/src/app/app.module.ts
+++ b/alfa-client/apps/admin/src/app/app.module.ts
@@ -1,8 +1,8 @@
 import { ApiRootModule } from '@alfa-client/api-root-shared';
-import { ENVIRONMENT_CONFIG, EnvironmentModule } from '@alfa-client/environment-shared';
+import { EnvironmentModule } from '@alfa-client/environment-shared';
 import { CommonModule } from '@angular/common';
-import { HttpClientModule } from '@angular/common/http';
-import { APP_INITIALIZER, NgModule } from '@angular/core';
+import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
+import { NgModule } from '@angular/core';
 import { BrowserModule } from '@angular/platform-browser';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { RouterModule } from '@angular/router';
@@ -11,16 +11,16 @@ import { StoreRouterConnectingModule } from '@ngrx/router-store';
 import { StoreModule } from '@ngrx/store';
 import { StoreDevtoolsModule } from '@ngrx/store-devtools';
 import { TestbtnComponent } from 'design-system';
-import { KeycloakAngularModule, KeycloakService } from 'keycloak-angular';
 import { environment } from '../environments/environment';
 import { AppComponent } from './app.component';
-import { initializeKeycloak } from './app.config';
 import { appRoutes } from './app.routes';
 import { PostfachPageComponent } from '../pages/postfach/postfach-page/postfach-page.component';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { UserProfileButtonContainerComponent } from '../common/user-profile-button-container/user-profile.button-container.component';
 import { AdminSettingsModule } from '@admin-client/admin-settings';
 import { PostfachNavigationItemComponent } from '../pages/postfach/postfach-navigation-item/postfach-navigation-item.component';
+import { OAuthModule } from 'angular-oauth2-oidc';
+import { HttpUnauthorizedInterceptor } from 'libs/authentication/src/lib/http-unauthorized.interceptor';
 
 @NgModule({
   declarations: [
@@ -36,7 +36,6 @@ import { PostfachNavigationItemComponent } from '../pages/postfach/postfach-navi
     BrowserModule,
     BrowserAnimationsModule,
     HttpClientModule,
-    KeycloakAngularModule,
     ApiRootModule,
     EnvironmentModule,
     environment.production ? [] : StoreDevtoolsModule.instrument(),
@@ -46,13 +45,17 @@ import { PostfachNavigationItemComponent } from '../pages/postfach/postfach-navi
     FormsModule,
     ReactiveFormsModule,
     AdminSettingsModule,
+    OAuthModule.forRoot({
+      resourceServer: {
+        sendAccessToken: true,
+      },
+    }),
   ],
   providers: [
     {
-      provide: APP_INITIALIZER,
-      useFactory: initializeKeycloak,
+      provide: HTTP_INTERCEPTORS,
+      useClass: HttpUnauthorizedInterceptor,
       multi: true,
-      deps: [KeycloakService, ENVIRONMENT_CONFIG],
     },
   ],
   bootstrap: [AppComponent],
diff --git a/alfa-client/apps/admin/src/common/auth/auth.service.spec.ts b/alfa-client/apps/admin/src/common/auth/auth.service.spec.ts
deleted file mode 100644
index 8d44ffa2b0eb2c1d0d5853bd506f846ba5920454..0000000000000000000000000000000000000000
--- a/alfa-client/apps/admin/src/common/auth/auth.service.spec.ts
+++ /dev/null
@@ -1,164 +0,0 @@
-import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
-import { AuthService } from './auth.service';
-import { KeycloakService, KeycloakEvent, KeycloakEventType } from 'keycloak-angular';
-import { of } from 'rxjs';
-import { KeycloakProfile } from 'keycloak-js';
-import { StateResource, createStateResource } from '@alfa-client/tech-shared';
-import { UserProfileResource } from '@alfa-client/user-profile-shared';
-import { createUserProfileResource } from '../../../../../libs/user-profile-shared/test/user-profile';
-
-describe('AuthService', () => {
-  let service: AuthService;
-  let keycloakService: Mock<KeycloakService>;
-
-  const event: KeycloakEvent = <any>{};
-
-  beforeEach(() => {
-    keycloakService = { ...mock(KeycloakService), keycloakEvents$: <any>of(event) };
-
-    service = new AuthService(useFromMock(keycloakService));
-  });
-
-  describe('listenToKeycloakEvent', () => {
-    it('should call handleEvent', () => {
-      service.handleEvent = jest.fn();
-
-      service.listenToKeycloakEvent();
-
-      expect(service.handleEvent).toHaveBeenCalledWith(event);
-    });
-  });
-
-  describe('handleEvent', () => {
-    describe('on token expired event', () => {
-      const tokenExpiredEvent: KeycloakEvent = { type: KeycloakEventType.OnTokenExpired };
-
-      it('should updateToken', () => {
-        service.handleEvent(tokenExpiredEvent);
-
-        expect(keycloakService.updateToken).toHaveBeenCalledWith(10);
-      });
-
-      it('should call handleTokenExpireEvent', async () => {
-        const updateTokenReturnValue: boolean = true;
-        service.handleTokenExpiredEvent = jest.fn();
-        keycloakService.updateToken.mockImplementation(() =>
-          Promise.resolve(updateTokenReturnValue),
-        );
-
-        await service.handleEvent(tokenExpiredEvent);
-
-        expect(service.handleTokenExpiredEvent).toHaveBeenCalledWith(updateTokenReturnValue);
-      });
-    });
-  });
-
-  describe('handleTokenExpiredEvent', () => {
-    it('should getToken if refresh was success', () => {
-      service.handleTokenExpiredEvent(true);
-
-      expect(keycloakService.getToken).toHaveBeenCalled();
-    });
-
-    it('should store token', async () => {
-      const token: string = 'tokenDummy';
-      service.storeAccessToken = jest.fn();
-      keycloakService.getToken.mockImplementation(() => Promise.resolve(token));
-
-      await service.handleTokenExpiredEvent(true);
-
-      expect(service.storeAccessToken).toHaveBeenCalledWith(token);
-    });
-  });
-
-  describe('login', () => {
-    it('should call isLoggedIn', () => {
-      service.login();
-
-      expect(keycloakService.isLoggedIn());
-    });
-
-    describe('after loggedIn', () => {
-      const isLoggedIn: boolean = true;
-
-      beforeEach(() => {
-        keycloakService.isLoggedIn.mockImplementation(() => Promise.resolve(isLoggedIn));
-        service.setCurrentUser = jest.fn();
-      });
-      it('should store token', async () => {
-        const token: string = 'tokenDummy';
-        keycloakService.getToken.mockImplementation(() => Promise.resolve(token));
-        service.storeAccessToken = jest.fn();
-
-        await service.login();
-
-        expect(service.storeAccessToken).toHaveBeenCalledWith(token);
-      });
-
-      it('should set currentUser', async () => {
-        await service.login();
-
-        expect(service.setCurrentUser).toHaveBeenCalled();
-      });
-    });
-    describe('if not logged in yet', () => {
-      it('should call login', async () => {
-        const isLoggedIn: boolean = false;
-        keycloakService.isLoggedIn.mockImplementation(() => Promise.resolve(isLoggedIn));
-
-        await service.login();
-
-        expect(keycloakService.login).toHaveBeenCalledWith({ scope: 'offline_access' });
-      });
-    });
-  });
-
-  describe('store access token', () => {
-    it('should put token in sessionStorage', () => {
-      const token: string = 'tokenDummy';
-
-      service.storeAccessToken(token);
-
-      const accessTokenInSessionStorage: string = sessionStorage.getItem('access_token');
-
-      expect(accessTokenInSessionStorage).toStrictEqual(token);
-    });
-  });
-  describe('logout', () => {
-    it('should call keycloakservice logout', () => {
-      service.logout();
-
-      expect(keycloakService.logout).toHaveBeenCalled();
-    });
-  });
-
-  describe('set current user', () => {
-    it('should load user profile', () => {
-      service.setCurrentUser();
-
-      expect(keycloakService.loadUserProfile).toHaveBeenCalled();
-    });
-    it('should update current user state resource', async () => {
-      const profile: KeycloakProfile = { firstName: 'blubb', lastName: 'blabb' };
-      keycloakService.loadUserProfile.mockImplementation(() => Promise.resolve(profile));
-
-      await service.setCurrentUser();
-
-      expect(service.currentUserStateResource()).toEqual(createStateResource(profile));
-    });
-  });
-
-  describe('getCurrentUserInitials', () => {
-    it('should return currentUserStateResource', () => {
-      const userProfile: UserProfileResource = createUserProfileResource();
-      const userStateResource: StateResource<UserProfileResource> =
-        createStateResource(userProfile);
-      service.currentUserStateResource.set(userStateResource);
-      const currentUserInitials: string = service.getCurrentUserInitials();
-
-      const initials: string =
-        userProfile.firstName.substring(0, 1) + '' + userProfile.lastName.substring(0, 1);
-      expect(currentUserInitials).toEqual(initials);
-    });
-  });
-});
diff --git a/alfa-client/apps/admin/src/common/auth/auth.service.ts b/alfa-client/apps/admin/src/common/auth/auth.service.ts
deleted file mode 100644
index 6f7ceb589abc8064c61f878dda5494f2051c5d52..0000000000000000000000000000000000000000
--- a/alfa-client/apps/admin/src/common/auth/auth.service.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import {
-  StateResource,
-  createEmptyStateResource,
-  createStateResource,
-} from '@alfa-client/tech-shared';
-import { Injectable, WritableSignal, signal } from '@angular/core';
-import { KeycloakEvent, KeycloakEventType, KeycloakService } from 'keycloak-angular';
-import { KeycloakProfile } from 'keycloak-js';
-import { UserProfileResource } from 'libs/user-profile-shared/src/lib/user-profile.model';
-import { getUserNameInitials } from 'libs/user-profile-shared/src/lib/user-profile.util';
-
-@Injectable({ providedIn: 'root' })
-export class AuthService {
-  currentUserStateResource: WritableSignal<StateResource<UserProfileResource>> = signal<
-    StateResource<UserProfileResource>
-  >(createEmptyStateResource());
-
-  public isLoggedIn = false;
-
-  constructor(private keycloak: KeycloakService) {
-    this.listenToKeycloakEvent();
-  }
-
-  listenToKeycloakEvent(): void {
-    this.keycloak.keycloakEvents$.subscribe((event: KeycloakEvent) => this.handleEvent(event));
-  }
-
-  async handleEvent(event: KeycloakEvent): Promise<void> {
-    if (event.type === KeycloakEventType.OnTokenExpired) {
-      await this.keycloak
-        .updateToken(10)
-        .then((refreshed) => this.handleTokenExpiredEvent(refreshed));
-    }
-  }
-
-  async handleTokenExpiredEvent(refreshed: boolean): Promise<void> {
-    if (refreshed) {
-      await this.keycloak.getToken().then((token) => this.storeAccessToken(token));
-    }
-  }
-
-  public async login(): Promise<void> {
-    this.isLoggedIn = await this.keycloak.isLoggedIn();
-    if (this.isLoggedIn) {
-      const token: string = await this.keycloak.getToken();
-      this.storeAccessToken(token);
-      await this.setCurrentUser();
-    } else {
-      this.keycloak.login({ scope: 'offline_access' });
-    }
-  }
-
-  storeAccessToken(token: string): void {
-    sessionStorage.setItem('access_token', token);
-  }
-
-  async setCurrentUser(): Promise<void> {
-    const profile: KeycloakProfile = await this.keycloak.loadUserProfile();
-
-    this.currentUserStateResource.set(createStateResource(this.buildUserProfileResource(profile)));
-  }
-
-  private buildUserProfileResource(profile: KeycloakProfile): UserProfileResource {
-    return <any>{
-      firstName: profile.firstName,
-      lastName: profile.lastName,
-    };
-  }
-
-  public logout(): void {
-    this.keycloak.logout();
-  }
-
-  public getCurrentUserInitials(): string {
-    return getUserNameInitials(this.currentUserStateResource().resource);
-  }
-}
diff --git a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.html b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.html
index e1e3a249b36d73847158d3245a0337ada0d48063..e27ec82f62a522e589002e75ed0830ed483ed079 100644
--- a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.html
+++ b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.html
@@ -1,6 +1,10 @@
 <div class="dropdown">
-  <button (click)="showDropDown()" class="dropbtn" data-test-id="drop-down-button">{{ currentUserInitials }}</button>
+  <button (click)="showDropDown()" class="dropbtn" data-test-id="drop-down-button">
+    {{ currentUserInitials }}
+  </button>
   <div id="myDropdown" class="dropdown-content">
-    <span style="cursor: pointer" (click)="authService.logout()" data-test-id="logout">Abmelden</span>
+    <span style="cursor: pointer" (click)="authenticationService.logout()" data-test-id="logout"
+      >Abmelden</span
+    >
   </div>
 </div>
diff --git a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts
index 95ea94f355b6c2918b543cdf401c10bef55b9fcf..f96d0b911d20d6e9c4da08c2c7cce135b3d4f863 100644
--- a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts
+++ b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts
@@ -6,15 +6,15 @@ import {
 } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { RouterTestingModule } from '@angular/router/testing';
-import { AuthService } from '../auth/auth.service';
 import { UserProfileButtonContainerComponent } from './user-profile.button-container.component';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { AuthenticationService } from 'authentication';
 
 describe('UserProfileButtonContainerComponent', () => {
   let component: UserProfileButtonContainerComponent;
   let fixture: ComponentFixture<UserProfileButtonContainerComponent>;
 
-  const authService: Mock<AuthService> = mock(AuthService);
+  const authenticationService: Mock<AuthenticationService> = mock(AuthenticationService);
 
   const dropDownButton: string = getDataTestIdOf('drop-down-button');
   const logout: string = getDataTestIdOf('logout');
@@ -25,8 +25,8 @@ describe('UserProfileButtonContainerComponent', () => {
       imports: [RouterTestingModule],
       providers: [
         {
-          provide: AuthService,
-          useValue: authService,
+          provide: AuthenticationService,
+          useValue: authenticationService,
         },
       ],
     }).compileComponents();
@@ -46,7 +46,7 @@ describe('UserProfileButtonContainerComponent', () => {
     it('should call authService to get current user initials', () => {
       component.ngOnInit();
 
-      expect(authService.getCurrentUserInitials).toHaveBeenCalled();
+      expect(authenticationService.getCurrentUserInitials).toHaveBeenCalled();
     });
   });
 
@@ -66,7 +66,7 @@ describe('UserProfileButtonContainerComponent', () => {
       fixture.detectChanges();
 
       const buttonElement: HTMLElement = getElementFromFixture(fixture, dropDownButton);
-      expect(buttonElement.textContent).toEqual('AV');
+      expect(buttonElement.textContent.trim()).toEqual('AV');
     });
   });
 
@@ -74,7 +74,7 @@ describe('UserProfileButtonContainerComponent', () => {
     it('should call authService logout', () => {
       dispatchEventFromFixture(fixture, logout, 'click');
 
-      expect(authService.logout).toHaveBeenCalled();
+      expect(authenticationService.logout).toHaveBeenCalled();
     });
   });
 });
diff --git a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile.button-container.component.ts b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile.button-container.component.ts
index 5e64bef4c865e11f97e41c3ee59f54f7cf956a2c..e61c01de1c3797616a0fad8d69ccc375af2bb39d 100644
--- a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile.button-container.component.ts
+++ b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile.button-container.component.ts
@@ -1,5 +1,5 @@
 import { Component, OnInit } from '@angular/core';
-import { AuthService } from '../auth/auth.service';
+import { AuthenticationService } from 'libs/authentication/src/lib/authentication.service';
 
 @Component({
   selector: 'user-profile-button-container',
@@ -9,10 +9,10 @@ import { AuthService } from '../auth/auth.service';
 export class UserProfileButtonContainerComponent implements OnInit {
   public currentUserInitials: string;
 
-  constructor(public authService: AuthService) {}
+  constructor(public authenticationService: AuthenticationService) {}
 
   ngOnInit(): void {
-    this.currentUserInitials = this.authService.getCurrentUserInitials();
+    this.currentUserInitials = this.authenticationService.getCurrentUserInitials();
   }
 
   public showDropDown(): void {
diff --git a/alfa-client/apps/admin/src/main.ts b/alfa-client/apps/admin/src/main.ts
index 5e03b925b784465a49e2f49ead63c0801124b6b0..3199db2879e8a93ad807dd20615329948b7e0373 100644
--- a/alfa-client/apps/admin/src/main.ts
+++ b/alfa-client/apps/admin/src/main.ts
@@ -14,9 +14,6 @@ loadEnvironment(environment.environmentUrl).then((env) => {
   if (env.production) {
     enableProdMode();
   }
-  console.info('init bootstrap application...');
-  //Für Standalone AppComponent
-  //bootstrapApplication(AppComponent, appConfig).catch(err => console.error(err));
   platformBrowserDynamic()
     .bootstrapModule(AppModule)
     .catch((err) => console.log(err));
diff --git a/alfa-client/apps/alfa-e2e/Jenkinsfile b/alfa-client/apps/alfa-e2e/Jenkinsfile
index eca38dd16248ecdb8ffd648482e74a0cbbd5f168..3c6516e22b426719c7453bacf30da69c60eb0826 100644
--- a/alfa-client/apps/alfa-e2e/Jenkinsfile
+++ b/alfa-client/apps/alfa-e2e/Jenkinsfile
@@ -203,14 +203,17 @@ pipeline {
             }
         }
 
-        stage('Run E2E-Tests') {
-            when {
-                expression { !SKIP_RUN }
-            }
-            failFast false
+//        stage('Run E2E-Tests') {
+//            when {
+//                expression { !SKIP_RUN }
+//            }
+//            failFast false
 
-            parallel {
+//            parallel {
                 stage('E2E-EA') {
+                    when {
+                        expression { !SKIP_RUN }
+                    }
                     steps {
                         catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
                             script {
@@ -238,6 +241,9 @@ pipeline {
                 }
 
                 stage('E2E-Main') {
+                    when {
+                        expression { !SKIP_RUN }
+                    }
                     steps {
                         catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
                             script {
@@ -263,8 +269,8 @@ pipeline {
                         }
                     }
                 }
-            }
-        }
+//            }
+//        }
 
         stage('Delete E2E Namespaces') {
             when {
@@ -452,9 +458,6 @@ Void generateNamespaceYaml(String bezeichner, String valuesPathSuffix, String us
 
 		envValues.user_manager.put("image", ['tag': env.USER_MANAGER_IMAGE_TAG])
 		envValues.user_manager.put("helm", ['version': env.USER_MANAGER_HELM_CHART_VERSION, 'repoUrl': env.USER_MANAGER_HELM_REPO_URL])
-
-		envValues.alfa.sso.put("keycloak_groups", generateKeycloakGroupsForHelmChart())
-		envValues.alfa.sso.put("keycloak_users", generateKeycloakUserForHelmChart(userFolder))
 	}
 
     writeYaml file: "gitops/dev/namespace/namespaces/by-${bezeichner}-dev.yaml", data: envValues, overwrite: true
@@ -467,66 +470,6 @@ Void generateNamespaceYaml(String bezeichner, String valuesPathSuffix, String us
     }
 }
 
-List generateKeycloakUserForHelmChart(String userFolder) {
-    def helmUsers = []
-
-    readUsersFixtures(userFolder).each { username, userFixture ->
-        def user = [
-            "name"      : userFixture.name,
-            "password"  : userFixture.password,
-            "first_name": userFixture.get("firstName", ""),
-            "last_name" : userFixture.get("lastName", ""),
-            "email"     : userFixture.get("email", "")
-        ]
-
-        if (userFixture.containsKey("clientRoles")) {
-            user.put("client_roles", mapUserClientRoles(userFixture.clientRoles))
-        }
-
-        if (userFixture.containsKey("groups")) {
-            user.put("groups", userFixture.groups)
-        }
-
-        helmUsers.add(user)
-    }
-
-    return helmUsers
-}
-
-List mapUserClientRoles(userClientRoles) {
-    def clientRoles = []
-
-    for(clientRole in userClientRoles) {
-        clientRoles.add(['name': 'alfa', 'role': clientRole])
-    }
-
-    return clientRoles
-}
-
-List generateKeycloakGroupsForHelmChart() {
-    def groupFiles = sh (script: 'ls src/fixtures/group', returnStdout: true)
-
-    def helmGroups = []
-
-    groupFiles.split("\\n").each { groupFile ->
-        def groupJson = readJSON file: "src/fixtures/group/${groupFile}"
-        def group = ["name": groupJson.name]
-
-        groupJson.attributes.each { key, values ->
-            if (!group.containsKey("attributes")) {
-                group.put("attributes", [["name": key, "value": values]])
-            }
-            else {
-                group.attributes.add(["name": key, "value": values])
-            }
-        }
-
-        helmGroups.add(group)
-    }
-
-    return helmGroups
-}
-
 Void deleteOzgCloudStack(ozgCloudBezeichner) {
     for(bezeichner in ozgCloudBezeichner) {
         if (hasNamespaceFile(bezeichner)) {
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-wiedereroeffnen.ea.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-wiedereroeffnen.ea.cy.ts
index 24108803003bd16018090b7b71ee0e9a6180c29d..1f5f74d71c2f8ef90e78c0332c01d5d206cf0969 100644
--- a/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-wiedereroeffnen.ea.cy.ts
+++ b/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-wiedereroeffnen.ea.cy.ts
@@ -106,11 +106,10 @@ describe('Vorgang wiedereroeffnen', () => {
         });
 
         it('should have status In Bearbeitung', () => {
-          vorgangPage
-            .getVorgangDetailHeader()
-            .getStatus()
-            .should('exist')
-            .should('have.text', vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG]);
+          haveText(
+            vorgangPage.getVorgangDetailHeader().getStatus(),
+            vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG],
+          );
         });
 
         it('back to vorgang list', () => {
diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-ea-dev.yaml b/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-ea-dev.yaml
index 20927351eff8ee54afdc44510f6c2ef4e6304cf2..c51a91fbe8027ec15a23a83008bb94c0ca39b838 100644
--- a/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-ea-dev.yaml
+++ b/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-ea-dev.yaml
@@ -6,20 +6,25 @@ project:
   destinations:
     - namespace: '*'
       server: https://kubernetes.default.svc
+
 alfa:
   env:
     overrideSpringProfiles: 'oc,ea,e2e,dev'
   sso:
-    serverUrl: https://sso.dev.by.ozg-cloud.de
-    apiPassword: 'Test1234!'
     keycloak_clients:
       - client_name: alfa
         client_roles:
           - name: EINHEITLICHER_ANSPRECHPARTNER
+    keycloak_users:
+      - name: emil
+        first_name: Emil
+        last_name: Ansprechpartner
+        password: "Y9nk43yrQ_zzIPpfFU-I"
+        client_roles:
+          - name: alfa
+            role: EINHEITLICHER_ANSPRECHPARTNER
   ingress:
     use_staging_cert: true
-    className: openshift-default
-  baseUrl: dev.by.ozg-cloud.de
 
 vorgang_manager:
   env:
@@ -44,28 +49,8 @@ user_manager:
   ozgcloud:
     usersync:
       onstart: true
-    keycloak:
-      api:
-        password: 'Test1234!'
-  sso:
-    serverUrl: https://sso.dev.by.ozg-cloud.de
-    api_user:
-      name: usermanagerapiuser
-      first_name: UserManager
-      last_name: ApiUser
-      realm_roles:
-        - offline_access
-        - uma_authorization
-      client_roles:
-        - name: realm-management
-          role: view-users
-        - name: realm-management
-          role: manage-users
-  baseUrl: dev.by.ozg-cloud.de
-
   ingress:
     use_staging_cert: true
-    className: openshift-default
 
 smocker:
   enabled: false
diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml b/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml
index c7234b086328954fdd04f1754e44d79cdc5d22a4..569f411da3884478eefd25a7e5636e906673a860 100644
--- a/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml
+++ b/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml
@@ -9,13 +9,8 @@ project:
 alfa:
   env:
     overrideSpringProfiles: 'oc,e2e,dev'
-  sso:
-    serverUrl: https://sso.dev.by.ozg-cloud.de
-    apiPassword: 'Test1234!'
   ingress:
     use_staging_cert: true
-    className: openshift-default
-  baseUrl: dev.by.ozg-cloud.de
 
 vorgang_manager:
   env:
@@ -40,28 +35,8 @@ user_manager:
   ozgcloud:
     usersync:
       onstart: true
-    keycloak:
-      api:
-        password: 'Test1234!'
-  sso:
-    serverUrl: https://sso.dev.by.ozg-cloud.de
-    api_user:
-      name: usermanagerapiuser
-      first_name: UserManager
-      last_name: ApiUser
-      realm_roles:
-        - offline_access
-        - uma_authorization
-      client_roles:
-        - name: realm-management
-          role: view-users
-        - name: realm-management
-          role: manage-users
-  baseUrl: dev.by.ozg-cloud.de
-
   ingress:
     use_staging_cert: true
-    className: openshift-default
 
 smocker:
   enabled: false
diff --git a/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts b/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts
index 935ac6d7042933627651ef0d7aa425ff9ab7b183..9d4300f76bf0b807f639f732bd36902d7406aa35 100644
--- a/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts
+++ b/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts
@@ -41,7 +41,7 @@ export function notExist(element: any): void {
 }
 
 export function haveText(element: any, text: string): void {
-  element.should('have.text', text);
+  element.invoke("text").then((elementText) => elementText.trim()).should("equal", text);
 }
 
 export function haveValue(element: any, value: string): void {
diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach.formservice.ts b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach.formservice.ts
index 53829e1fce73f0d3dbb83fcb30d91fafc1a576d0..3e795f982fbc6d9f97d5d2e44e2b73f20a535261 100644
--- a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach.formservice.ts
+++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach.formservice.ts
@@ -33,7 +33,6 @@ export class PostfachFormService extends AbstractFormService {
   }
 
   protected doSubmit(): Observable<StateResource<Resource>> {
-    console.info('FormValue: ', this.getFormValue());
     return of(createEmptyStateResource<Resource>());
   }
 
diff --git a/alfa-client/libs/authentication/.eslintrc.json b/alfa-client/libs/authentication/.eslintrc.json
new file mode 100644
index 0000000000000000000000000000000000000000..b953e5d37d40148217ab14a01859ea0cb43d9ebc
--- /dev/null
+++ b/alfa-client/libs/authentication/.eslintrc.json
@@ -0,0 +1,33 @@
+{
+  "extends": ["../../.eslintrc.json"],
+  "ignorePatterns": ["!**/*"],
+  "overrides": [
+    {
+      "files": ["*.ts"],
+      "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
+      "rules": {
+        "@angular-eslint/directive-selector": [
+          "error",
+          {
+            "type": "attribute",
+            "prefix": "lib",
+            "style": "camelCase"
+          }
+        ],
+        "@angular-eslint/component-selector": [
+          "error",
+          {
+            "type": "element",
+            "prefix": "lib",
+            "style": "kebab-case"
+          }
+        ]
+      }
+    },
+    {
+      "files": ["*.html"],
+      "extends": ["plugin:@nx/angular-template"],
+      "rules": {}
+    }
+  ]
+}
diff --git a/alfa-client/libs/authentication/README.md b/alfa-client/libs/authentication/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..927d463c287071179f81c12ec68a6f88fb777e18
--- /dev/null
+++ b/alfa-client/libs/authentication/README.md
@@ -0,0 +1,7 @@
+# authentication
+
+This library was generated with [Nx](https://nx.dev).
+
+## Running unit tests
+
+Run `nx test authentication` to execute the unit tests.
diff --git a/alfa-client/libs/authentication/jest.config.ts b/alfa-client/libs/authentication/jest.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3d9be36ab97b9dcdffca41df8ae346c05abbc719
--- /dev/null
+++ b/alfa-client/libs/authentication/jest.config.ts
@@ -0,0 +1,22 @@
+/* eslint-disable */
+export default {
+  displayName: 'authentication',
+  preset: '../../jest.preset.js',
+  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
+  coverageDirectory: '../../coverage/libs/authentication',
+  transform: {
+    '^.+\\.(ts|mjs|js|html)$': [
+      'jest-preset-angular',
+      {
+        tsconfig: '<rootDir>/tsconfig.spec.json',
+        stringifyContentPathRegex: '\\.(html|svg)$',
+      },
+    ],
+  },
+  transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+  snapshotSerializers: [
+    'jest-preset-angular/build/serializers/no-ng-attributes',
+    'jest-preset-angular/build/serializers/ng-snapshot',
+    'jest-preset-angular/build/serializers/html-comment',
+  ],
+};
diff --git a/alfa-client/libs/authentication/project.json b/alfa-client/libs/authentication/project.json
new file mode 100644
index 0000000000000000000000000000000000000000..32c2f511abfdc54eaf66bbff2b72e38af9484fad
--- /dev/null
+++ b/alfa-client/libs/authentication/project.json
@@ -0,0 +1,31 @@
+{
+  "name": "authentication",
+  "$schema": "../../node_modules/nx/schemas/project-schema.json",
+  "sourceRoot": "libs/authentication/src",
+  "prefix": "lib",
+  "tags": [],
+  "projectType": "library",
+  "targets": {
+    "test": {
+      "executor": "@nx/jest:jest",
+      "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
+      "options": {
+        "jestConfig": "libs/authentication/jest.config.ts",
+        "passWithNoTests": true
+      },
+      "configurations": {
+        "ci": {
+          "ci": true,
+          "codeCoverage": true
+        }
+      }
+    },
+    "lint": {
+      "executor": "@nx/eslint:lint",
+      "outputs": ["{options.outputFile}"],
+      "options": {
+        "lintFilePatterns": ["libs/authentication/**/*.ts", "libs/authentication/**/*.html"]
+      }
+    }
+  }
+}
diff --git a/alfa-client/libs/authentication/src/index.ts b/alfa-client/libs/authentication/src/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0cba51147eaa7a921027ceb37672deac3ed07be3
--- /dev/null
+++ b/alfa-client/libs/authentication/src/index.ts
@@ -0,0 +1,2 @@
+export * from './lib/authentication.module';
+export * from './lib/authentication.service';
diff --git a/alfa-client/libs/authentication/src/lib/authentication.module.spec.ts b/alfa-client/libs/authentication/src/lib/authentication.module.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5dc84817fd14e1d2306ccc6aa6cb62e1f9e79eb0
--- /dev/null
+++ b/alfa-client/libs/authentication/src/lib/authentication.module.spec.ts
@@ -0,0 +1,14 @@
+import { AuthenticationModule } from './authentication.module';
+import { TestBed } from '@angular/core/testing';
+
+describe('AuthenticationModule', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      imports: [AuthenticationModule],
+    }).compileComponents();
+  });
+
+  it('should create', () => {
+    expect(AuthenticationModule).toBeDefined();
+  });
+});
diff --git a/alfa-client/libs/authentication/src/lib/authentication.module.ts b/alfa-client/libs/authentication/src/lib/authentication.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9dd1d02ea48c35dcc1a7a86c4e77718233578d9b
--- /dev/null
+++ b/alfa-client/libs/authentication/src/lib/authentication.module.ts
@@ -0,0 +1,9 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { HttpUnauthorizedInterceptor } from './http-unauthorized.interceptor';
+
+@NgModule({
+  imports: [CommonModule],
+  providers: [HttpUnauthorizedInterceptor],
+})
+export class AuthenticationModule {}
diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..16b30c377fd4926c36a7d15d8cb4c635f08f7b00
--- /dev/null
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
@@ -0,0 +1,110 @@
+import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
+import { UserProfileResource } from '@alfa-client/user-profile-shared';
+import { createUserProfileResource } from '../../../../libs/user-profile-shared/test/user-profile';
+import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
+import { fakeAsync, tick } from '@angular/core/testing';
+import { AuthenticationService } from './authentication.service';
+import { createAuthConfig } from '../../test/authentication.test';
+import { createEnvironment } from '../../../environment-shared/test/environment';
+
+describe('AuthenticationService', () => {
+  let service: AuthenticationService;
+  let oAuthService: Mock<OAuthService>;
+  let environmentConfig;
+
+  beforeEach(() => {
+    oAuthService = <any>{
+      ...mock(OAuthService),
+      loadDiscoveryDocumentAndLogin: jest.fn().mockResolvedValue(() => Promise.resolve()),
+    };
+    environmentConfig = createEnvironment();
+
+    service = new AuthenticationService(useFromMock(oAuthService), environmentConfig);
+  });
+
+  describe('login', () => {
+    it('should configure service with authConfig', () => {
+      const authConfig: AuthConfig = createAuthConfig();
+      service.buildConfiguration = jest.fn().mockReturnValue(authConfig);
+
+      service.login();
+
+      expect(oAuthService.configure).toHaveBeenCalledWith(authConfig);
+    });
+
+    it('should setup automatic silent refresh', () => {
+      service.login();
+
+      expect(oAuthService.setupAutomaticSilentRefresh).toHaveBeenCalled();
+    });
+
+    it('should set tokenValidator', () => {
+      oAuthService.tokenValidationHandler = null;
+
+      service.login();
+
+      expect(oAuthService.tokenValidationHandler).not.toBeNull();
+    });
+
+    it('should load discovery document and login', () => {
+      service.login();
+
+      expect(oAuthService.loadDiscoveryDocumentAndLogin).toHaveBeenCalled();
+    });
+
+    it('should set current user', fakeAsync(() => {
+      service.setCurrentUser = jest.fn();
+
+      service.login();
+      tick();
+
+      expect(service.setCurrentUser).toHaveBeenCalled();
+    }));
+  });
+
+  describe('set current user', () => {
+    const identityClaims: Record<string, any> = {
+      ['given_name']: 'Marco',
+      ['family_name']: 'Polo',
+    };
+
+    beforeEach(() => {
+      oAuthService.getIdentityClaims.mockReturnValue(identityClaims);
+    });
+    it('should call oAuthservice to get claims', () => {
+      service.setCurrentUser();
+
+      expect(oAuthService.getIdentityClaims).toHaveBeenCalled();
+    });
+
+    it('should update currentUser', () => {
+      service.setCurrentUser();
+
+      expect(service.currentUserResource.firstName).toEqual('Marco');
+      expect(service.currentUserResource.lastName).toEqual('Polo');
+    });
+  });
+
+  describe('getCurrentUserInitials', () => {
+    it('should return currentUserResource', () => {
+      const userProfile: UserProfileResource = {
+        ...createUserProfileResource(),
+        firstName: 'Marco',
+        lastName: 'Polo',
+      };
+      service.currentUserResource = userProfile;
+
+      const currentUserInitials: string = service.getCurrentUserInitials();
+
+      expect(currentUserInitials).toEqual('MP');
+    });
+  });
+
+  describe('logout', () => {
+    it('should call oAuthService revokeTokenAndLogout', () => {
+      service.logout();
+
+      expect(oAuthService.revokeTokenAndLogout).toHaveBeenCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.ts b/alfa-client/libs/authentication/src/lib/authentication.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0e45de7eec32e9788212415f86e98db6b5012fce
--- /dev/null
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.ts
@@ -0,0 +1,58 @@
+import { ENVIRONMENT_CONFIG, Environment } from '@alfa-client/environment-shared';
+import { Inject, Injectable } from '@angular/core';
+import { OAuthService, AuthConfig } 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';
+
+@Injectable({ providedIn: 'root' })
+export class AuthenticationService {
+  currentUserResource: UserProfileResource;
+
+  constructor(
+    private oAuthService: OAuthService,
+    @Inject(ENVIRONMENT_CONFIG) private envConfig: Environment,
+  ) {}
+
+  public async login(): Promise<void> {
+    this.oAuthService.configure(this.buildConfiguration());
+    this.oAuthService.setupAutomaticSilentRefresh();
+    this.oAuthService.tokenValidationHandler = new JwksValidationHandler();
+    await this.oAuthService.loadDiscoveryDocumentAndLogin();
+    this.setCurrentUser();
+  }
+
+  buildConfiguration(): AuthConfig {
+    return {
+      issuer: this.envConfig.authServer + '/realms/' + this.envConfig.realm,
+      tokenEndpoint:
+        this.envConfig.authServer +
+        '/realms/' +
+        this.envConfig.realm +
+        '/protocol/openid-connect/token',
+      redirectUri: window.location.origin + '/',
+      clientId: this.envConfig.clientId,
+      scope: 'openid profile',
+      requireHttps: false,
+      responseType: 'code',
+      showDebugInformation: false,
+    };
+  }
+
+  setCurrentUser(): void {
+    const claims: Record<string, any> = this.oAuthService.getIdentityClaims();
+    const userResource: UserProfileResource = <any>{
+      firstName: claims['given_name'],
+      lastName: claims['family_name'],
+    };
+    this.currentUserResource = userResource;
+  }
+
+  public getCurrentUserInitials(): string {
+    return getUserNameInitials(this.currentUserResource);
+  }
+
+  public logout(): void {
+    this.oAuthService.revokeTokenAndLogout();
+  }
+}
diff --git a/alfa-client/libs/authentication/src/lib/http-unauthorized.interceptor.spec.ts b/alfa-client/libs/authentication/src/lib/http-unauthorized.interceptor.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d22dd199212580a77eeab3506aa9d17d105546ea
--- /dev/null
+++ b/alfa-client/libs/authentication/src/lib/http-unauthorized.interceptor.spec.ts
@@ -0,0 +1,79 @@
+import { Mock, mock } from '@alfa-client/test-utils';
+import { TestBed } from '@angular/core/testing';
+import { MatDialogModule } from '@angular/material/dialog';
+import { HttpUnauthorizedInterceptor } from './http-unauthorized.interceptor';
+import { HttpErrorResponse, HttpHandler, HttpRequest } from '@angular/common/http';
+import { Subject, isEmpty } from 'rxjs';
+import { AuthenticationService } from './authentication.service';
+
+describe('HttpUnauthorizedInterceptor', () => {
+  let interceptor: HttpUnauthorizedInterceptor;
+
+  const authenticationService: Mock<AuthenticationService> = mock(AuthenticationService);
+
+  beforeEach(() =>
+    TestBed.configureTestingModule({
+      imports: [MatDialogModule],
+      providers: [
+        HttpUnauthorizedInterceptor,
+        {
+          provide: AuthenticationService,
+          useValue: authenticationService,
+        },
+      ],
+    }),
+  );
+
+  beforeEach(() => {
+    interceptor = TestBed.inject(HttpUnauthorizedInterceptor);
+  });
+
+  it('should be created', () => {
+    expect(interceptor).toBeTruthy();
+  });
+
+  describe('intercept', () => {
+    const error: HttpErrorResponse = new HttpErrorResponse({});
+
+    const handleSubject: Subject<any> = new Subject();
+    const httpHandler: HttpHandler = { handle: () => handleSubject };
+    const request: HttpRequest<unknown> = new HttpRequest('GET', '/test');
+
+    it('should call handleError with error', () => {
+      interceptor.handleError = jest.fn();
+
+      interceptor.intercept(request, httpHandler).subscribe();
+      handleSubject.error(error);
+
+      expect(interceptor.handleError).toHaveBeenCalledWith(error);
+    });
+  });
+
+  describe('handleError', () => {
+    describe('on unauthorized status', () => {
+      const unauthorizedError: any = new HttpErrorResponse({ status: 401 });
+
+      it('should call logout on authService ', () => {
+        interceptor.handleError(unauthorizedError);
+
+        expect(authenticationService.logout).toHaveBeenCalled();
+      });
+
+      it('should return EMPTY', (done) => {
+        interceptor
+          .handleError(unauthorizedError)
+          .pipe(isEmpty())
+          .subscribe((res) => {
+            expect(res).toBeTruthy;
+            done();
+          });
+      });
+    });
+
+    it('should rethrow error if not unauthorized status', () => {
+      const anyError: any = new HttpErrorResponse({ status: 500 });
+
+      expect(() => interceptor.handleError(anyError)).toThrowError();
+    });
+  });
+});
diff --git a/alfa-client/libs/authentication/src/lib/http-unauthorized.interceptor.ts b/alfa-client/libs/authentication/src/lib/http-unauthorized.interceptor.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0ce59555abc0f54337de086fdc3111c474935252
--- /dev/null
+++ b/alfa-client/libs/authentication/src/lib/http-unauthorized.interceptor.ts
@@ -0,0 +1,34 @@
+import {
+  HttpErrorResponse,
+  HttpEvent,
+  HttpHandler,
+  HttpInterceptor,
+  HttpRequest,
+} from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { isUnauthorized } from '@alfa-client/tech-shared';
+import { EMPTY, Observable } from 'rxjs';
+import { catchError } from 'rxjs/operators';
+import { AuthenticationService } from './authentication.service';
+
+@Injectable()
+export class HttpUnauthorizedInterceptor implements HttpInterceptor {
+  constructor(private authenticationService: AuthenticationService) {}
+
+  public intercept(
+    request: HttpRequest<unknown>,
+    next: HttpHandler,
+  ): Observable<HttpEvent<unknown>> {
+    return next
+      .handle(request)
+      .pipe(catchError((error: HttpErrorResponse) => this.handleError(error)));
+  }
+
+  handleError(error: HttpErrorResponse): Observable<any> {
+    if (isUnauthorized(error.status)) {
+      this.authenticationService.logout();
+      return EMPTY;
+    }
+    throw error;
+  }
+}
diff --git a/alfa-client/libs/authentication/src/test-setup.ts b/alfa-client/libs/authentication/src/test-setup.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e3361fb01b7b562d0a94995eb9c00a6ad5b2949d
--- /dev/null
+++ b/alfa-client/libs/authentication/src/test-setup.ts
@@ -0,0 +1,12 @@
+import 'jest-preset-angular/setup-jest';
+
+import { getTestBed } from '@angular/core/testing';
+import {
+  BrowserDynamicTestingModule,
+  platformBrowserDynamicTesting,
+} from '@angular/platform-browser-dynamic/testing';
+
+getTestBed().resetTestEnvironment();
+getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
+  teardown: { destroyAfterEach: false },
+});
diff --git a/alfa-client/libs/authentication/test/authentication.test.ts b/alfa-client/libs/authentication/test/authentication.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a33cb3c48a772b5327e9251eaa4a892743c7d2c2
--- /dev/null
+++ b/alfa-client/libs/authentication/test/authentication.test.ts
@@ -0,0 +1,5 @@
+import { AuthConfig } from 'angular-oauth2-oidc';
+
+export function createAuthConfig(): AuthConfig {
+  return {};
+}
diff --git a/alfa-client/libs/authentication/tsconfig.json b/alfa-client/libs/authentication/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..03261df5a47903bb7d4de17fbef9e9a14b048bed
--- /dev/null
+++ b/alfa-client/libs/authentication/tsconfig.json
@@ -0,0 +1,16 @@
+{
+  "extends": "../../tsconfig.base.json",
+  "files": [],
+  "include": [],
+  "references": [
+    {
+      "path": "./tsconfig.lib.json"
+    },
+    {
+      "path": "./tsconfig.spec.json"
+    }
+  ],
+  "compilerOptions": {
+    "target": "es2020"
+  }
+}
diff --git a/alfa-client/libs/authentication/tsconfig.lib.json b/alfa-client/libs/authentication/tsconfig.lib.json
new file mode 100644
index 0000000000000000000000000000000000000000..12787567547cf6ba3faf59c8257b0750964c8741
--- /dev/null
+++ b/alfa-client/libs/authentication/tsconfig.lib.json
@@ -0,0 +1,12 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../dist/out-tsc",
+    "declaration": true,
+    "declarationMap": true,
+    "inlineSources": true,
+    "types": []
+  },
+  "exclude": ["src/**/*.spec.ts", "src/test-setup.ts", "jest.config.ts", "src/**/*.test.ts"],
+  "include": ["src/**/*.ts", "test/authentication.test.ts"]
+}
diff --git a/alfa-client/libs/authentication/tsconfig.spec.json b/alfa-client/libs/authentication/tsconfig.spec.json
new file mode 100644
index 0000000000000000000000000000000000000000..5ad7a4c64f427f468da7e6a1b593fafd898ff25a
--- /dev/null
+++ b/alfa-client/libs/authentication/tsconfig.spec.json
@@ -0,0 +1,17 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../dist/out-tsc",
+    "module": "commonjs",
+    "target": "es2016",
+    "types": ["jest", "node"]
+  },
+  "files": ["src/test-setup.ts"],
+  "include": [
+    "jest.config.ts",
+    "src/**/*.test.ts",
+    "src/**/*.spec.ts",
+    "src/**/*.d.ts",
+    "test/authentication.test.ts"
+  ]
+}
diff --git a/alfa-client/tsconfig.base.json b/alfa-client/tsconfig.base.json
index 273aa6f0fd7e8b8dc7bfe7e87a4f644820431bf8..1f7364bba7606a74a3d102427b82bb77ac3049cb 100644
--- a/alfa-client/tsconfig.base.json
+++ b/alfa-client/tsconfig.base.json
@@ -53,6 +53,7 @@
       "@alfa-client/vorgang-shared-ui": ["libs/vorgang-shared-ui/src/index.ts"],
       "@alfa-client/wiedervorlage": ["libs/wiedervorlage/src/index.ts"],
       "@alfa-client/wiedervorlage-shared": ["libs/wiedervorlage-shared/src/index.ts"],
+      "authentication": ["libs/authentication/src/index.ts"],
       "design-system": ["libs/design-system/src/index.ts"]
     }
   },