Keycloak Integration with Angular APP

recipe book

This article will cover how to integrate the keycloak with angular app . There is an open source library which works quite well with angular app :

https://www.npmjs.com/package/keycloak-angular

I have my recipe-angular app in :

https://github.com/jokumar/angular-recipe.git

The required functionality of the app in terms of Keycloak is :

  • The angular app talks to recipe-service and user-service .
  • Home page can be accessed without login.
  • All the pages except home page are protected in app.routing.ts and would required authentication/authorization.
  • User will be redirected to keycloak login page where he enters the credentials .

Below are the steps to take to integrate keycloak in angular :

  • Install keycloak-angular 
npm install --save keycloak-angular@6.0.1

  • The keycloak service needs to be initialized during application loading .Hence we need an initializer function like below :
import {environment} from '../environments/environment';
import {KeycloakService} from 'keycloak-angular';

export function initializer(keycloak: KeycloakService): () => Promise<any> {
 return (): Promise<any> => {
   return new Promise(async (resolve, reject) => {
     try {
       await keycloak.init({
         config: environment.keycloakConfig,
         initOptions: {
           onLoad: 'check-sso',
           checkLoginIframe: false
         },
         enableBearerInterceptor: true,
         bearerPrefix: 'Bearer',
         bearerExcludedUrls: [
           'main.js',
         ]
       });
       resolve();
     } catch (error) {
       reject(error);
     }
   });
 };
}

  • Define the keycloak configuration in environment variable . Note the client id and secret . In this case it is the client id of the 3scale .
import {KeycloakConfig} from 'keycloak-angular';
export const kcConfig: KeycloakConfig = {
  url: 'https://sso-keycloak.geeks18/auth',
  realm: 'Staging-Realm',
  clientId: 'c5912b69',// This is the client id which got generated by the 3scale in Keycloak . This client id referes to 3scale client id
  credentials: {secret: 'cf6610b6e9fc8c665f89e510045fb8c3'},
};
  • Define the keycloak initializer in Appmodule 
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { KeycloakService, KeycloakAngularModule } from 'keycloak-angular';
import { initializer } from './utils/app-init';
   import { TokenInterceptor } from './services/token.interceptor';
   import { HTTP_INTERCEPTORS } from '@angular/common/http';

@NgModule({
  imports: [KeycloakAngularModule],
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initializer,
      multi: true,
      deps: [KeycloakService]
    }

  ]
})
  • Define the authentication Service and extend the AuthenticationService from KeycloakAuthguard . Override the isAccessAllowed and verify the authorization with the roles of the users.
isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
   return new Promise((resolve, reject) => {
     if (!this.authenticated) {
       this.keycloakAngular.login()
         .catch(e => console.error(e));
       return reject(false);
     }

     const requiredRoles: string[] = route.data.roles;
     if (!requiredRoles || requiredRoles.length === 0) {
       return resolve(true);
     } else {
       if (!this.roles || this.roles.length === 0) {
         resolve(false);
       }
       resolve(requiredRoles.every(role => this.roles.indexOf(role) > -1));
     }
   });
 }
  • Add the AuthenticationService in all the the routes except home component of app.routing.ts :
const routes: Routes = [
 { path: 'recipe-create', component: RecipeCreateComponent , canActivate: [AuthenticationService]},
 { path: 'recipes', component: RecipesComponent, canActivate: [AuthenticationService] },
 { path: 'ingredient-list', component: IngredientListComponent , canActivate: [AuthenticationService]},
 { path: 'ingredients', component: IngredientComponent , canActivate: [AuthenticationService]},
 { path: 'profile', component: ProfileComponent , canActivate: [AuthenticationService]},
 { path: '', component: HomeComponent},

];

Below is the snippet of the rest call for creating ingredients . The bearer token will be passed to the header by the angular-keycloak module on every rest invocation:

public getIngredients(ownerId?: string): Observable< Array< IngredientView > > {
   return Observable.create((observer) => {
     this.http.get(this.url + '/ingredient', {
       headers: new HttpHeaders({
         'Content-Type': 'application/json'

       }),
       observe: 'body',
     })
       .subscribe(
         (res: Array<Ingredient>) => {
           const ingredients: Array<IngredientView> = [];
           res = res ? res : [];
           res.forEach((ingredient: Ingredient) => {
             ingredients.push(new IngredientView(ingredient));
           });
           observer.next(ingredients);
           observer.complete();

         },
         (error) => {
           console.log(JSON.stringify(error));
           observer.error(error);
           observer.complete();
         });
   });
 }

start your angular app : npm start

Home page

Click on login at right top corner , you will be redirected to keycloak login page . Enter the credentials we used for the user we setup in last article .

After successful authentication , we will be redirected to recipe page where

angular app will fetch the recipes from the recipe-service with the token passed in the header .

Call to retrieve token
Token being passed on to HTTP header as bearer token

This is how we have the angular app secured with Keycloak

This concludes the series on microservice on openshift platform .

Reference to my github project :

https://github.com/jokumar/openshift-project

https://github.com/jokumar/angular-recipe

Please share your views . Thank you and Happy Coding .

Digiprove sealCopyright secured by Digiprove © 2020 Geeks 18

Be the first to comment

Leave a Reply

Your email address will not be published.


*