Angular Keycloak

From bibbleWiki
Jump to navigation Jump to search

Introduction

This is a page just to clarify how to integrate Keycloak with Angular. It is assumed you know how to configure Keycloak. Most of this is from ["Wojciech Krzywiec"]

Keycloak

So to set this up we

Application

Install the Keycloak Package

npm install keycloak-angular keycloak-js

Create Initializer Factory

Never keen on the CLI but I guess it stays up to date.

ng g class init/keycloak-init --type=factory --skip-tests

This provides the initializer for Keycloak Server

import { KeycloakService } from "keycloak-angular";

export function initializeKeycloak(
  keycloak: KeycloakService
  ) {
    return () =>
      keycloak.init({
        config: {
          url: 'http://localhost:8080' + '/auth',
          realm: 'test',
          clientId: 'frontend',
        }
      });
}

Now add it to the app module

@NgModule({
  declarations: [
    AppComponent,
    ContentComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatButtonModule,
    MatFormFieldModule,
    MatSelectModule,
    MatTableModule,
    MatSnackBarModule,
    HttpClientModule,
    KeycloakAngularModule,
    NgbModule,
    AppRoutingModule
  ],
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initializeKeycloak,
      multi: true,
      deps: [KeycloakService],
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Create a Guard

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard extends KeycloakAuthGuard {
  
  constructor(
    protected readonly router: Router,
    protected readonly keycloak: KeycloakService
  ) {
    super(router, keycloak);
  }
  
  async isAccessAllowed(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Promise<boolean | UrlTree> {
    
    if (!this.authenticated) {
      await this.keycloak.login({
        redirectUri: window.location.origin + state.url,
      });
    }

    return this.authenticated;
  }
}

Add the Guard to the Route

const routes: Routes = [
  { path: '', component: ContentComponent , canActivate: [AuthGuard]},
  { path: '**', redirectTo: '' }
];

CSP and Keycloak

The default installation I used had the Realm Settings->Security Defences with

These needed to be modified to work. To fix you are the host ip e.g. http://localhost:4200

Setup

Configuration Setup

We create a dev and production environment. Under assets/config

Dev config.dev.json

{
    "KEYCLOAK_URL": "http://localhost:8080",
    "KEYCLOAK_REALM": "test",
    "KEYCLOAK_CLIENT_ID": "frontend"
}

Prod config.prod.json

{
    "KEYCLOAK_URL": "${KEYCLOAK_URL}",
    "KEYCLOAK_REALM": "${KEYCLOAK_REALM}",
    "KEYCLOAK_CLIENT_ID": "${KEYCLOAK_CLIENT_ID}"
}

Environment Setup

Under Environments create a default (copy of dev) dev and production configuration

Prod environment.prod.ts

export const environment = {
  production: true,
  configFile: 'assets/config/config.prod.json'
};

Dev environment.dev.ts

export const environment = {
  production: false,
  configFile: 'assets/config/config.dev.json'
};