Blog

You are here: Blog / How to Integrate Identity Server to Angular Application


  • How to Integrate Identity Server to Angular Application

    Hire our expert Anuglar developer

    We are using Angular 8 Quick starter, first download Angular 8 CLI and then create our project. Consider that server side code has already been developed.

    Go to AngularCLI website and follow the steps.

    Step 1: Install the Angular CLI

    To install the CLI using npm, open a VS Code terminal/console window. If you are on a Mac or Linux type following command.

    PS E:\>npm install -g @angular/cli

    It takes some time to download the CLI and Installed the NPM packages.

    Step 2: Create workspace and initial application

    1. Run the CLI command ng new and provide the name my-app, as show below. As we are implementing Identity Server so I given a name as “identityServer-app”

      PS C:\> ng new identityServer-app

    2. The ng new command prompts you for information about features to include in the initial app project and here are the answers of each:

      PS C:\> ng new identityServer-app
      ? Would you like to add Angular routing? Yes
      ? Which stylesheet format would you like to use? SCSS   [ http://sass-lang.com/documentation/file.SASS_REFERENCE.html#syntax ]
      CREATE identityServer -app/angular.json (3958 bytes)
      CREATE identityServer -app/package.json (1313 bytes)

    This will create required folders to Up and Running with our Application and also install all the NPM packages. This will take some time to finish.

    Step 3: Install Oidc-client.js

    Go to workplace folder (identityServer-app) and type following command on your terminal to install the latest Oidc-client.js

    PS C:\identityServer-app> npm install oidc-client –save

    you’ll need the latest version of oidc-client, which you can see in package.json

    "oidc-client": "^1.10.1"	

    Step 4: Update the UserManagerSettings

    Create constant object called “ClientSettings” as per below code.

    export const ClientSettings = {
      authority: "http://localhost:5000",
      client_id: "identityserverapp",
      redirect_uri: "http://localhost:4200/auth-callback",
      post_logout_redirect_uri: "http://localhost:5000/account/login/",
      response_type: "code",
      scope: "openid profile api",
      filterProtocolClaims: true,
      loadUserInfo: true,
      automaticSilentRenew: true,
      silent_redirect_uri: 'http://localhost:4200/silent-refresh'
    }; 

    Required Settings

    • authority: The URL of the OIDC/OAuth2 provider. In our case our Server URL
    • client_id: Your client application's identifier as registered with the OIDC/OAuth2 provider. You can set whatever you want which will be verify by your server.
    • redirect_uri: The redirect URI of your client application to receive a response from the OIDC/OAuth2 provider.
    • response_type: (default: 'id_token'): The type of response desired from the OIDC/OAuth2 provider.
    • scope : (default: 'openid'): The scope being requested from the OIDC/OAuth2 provider.

    Other Optional Settings

    • loadUserInfo : (default: true): Flag to control if additional identity data is loaded from the user info endpoint in order to populate the user's profile.
    • filterProtocolClaims : (default: true): Should OIDC protocol claims be removed from profile.
    • post_logout_redirect_uri: The OIDC/OAuth2 post-logout redirect URI.
    • silent_redirect_uri: The URL for the page containing the code handling the silent renew.
    • automaticSilentRenew: (default: false): Flag to indicate if there is an automatic attempt to renew the access token prior to expiration. The attempt is made as a result of the accessTokenExpiring event being raised.

    Step 5: Create function to get Client Settings

    Below is content of the get client setting function which inherited UserManagerSettings class which is part of the oidc-client

    export function getClientSettings(): UserManagerSettings {
      return {
        authority: ClientSettings.authority,
        client_id: ClientSettings.client_id,
        redirect_uri: ClientSettings.redirect_uri,
        post_logout_redirect_uri: ClientSettings.post_logout_redirect_uri,
        response_type: ClientSettings.response_type,
        scope: ClientSettings.scope,
        filterProtocolClaims: ClientSettings.filterProtocolClaims,
        loadUserInfo: ClientSettings.loadUserInfo,
        automaticSilentRenew: ClientSettings.automaticSilentRenew,
        silent_redirect_uri:ClientSettings.silent_redirect_uri
      };
    }

    Step 6: Create auth.service file

    Create auth.service file and below is content of the auth.service.ts file.

    import { HttpClient } from "@angular/common/http";
    import { Injectable } from "@angular/core";
    import { User, UserManager, UserManagerSettings } from "oidc-client";
    import { BehaviorSubject } from "rxjs";
    
    @Injectable({
      providedIn: "root"
    })
    export class AuthService  {
      private _authNavStatusSource = new BehaviorSubject(false);
      authNavStatus$ = this._authNavStatusSource.asObservable();
    
      private manager = new UserManager(getClientSettings());
      private user: User | null;
    
      constructor(private http: HttpClient, private configService: ConfigService) {
        super();
     
        this.manager.getUser().then(user => {
          this.user = user;
          this._authNavStatusSource.next(this.isAuthenticated());
        });
      }
    
      login() {
        return this.manager.signinRedirect();
      }
    
      async completeAuthentication() {
        this.user = await this.manager.signinRedirectCallback();
        this._authNavStatusSource.next(this.isAuthenticated());
      }
      signinSilentCallback(){
        this.manager.signinSilentCallback()
        .catch((err) => {
          console.log(err);
      });
      }
    
      isAuthenticated(): boolean {
        return (this.user != null && !this.user.expired);
      }
    
      get authorizationHeaderValue(): string {
        return `${this.user.token_type} ${this.user.access_token}`;
      }
    
      get name(): string {
        if (this.user !== null && this.user.profile !== undefined){
          return  this.user.profile.name;
        } else {
          return "";
        }
      }
    
      async signout() {
        await this.manager.signoutRedirect();
      }
    }

    Here is description of each methods which has been used in auth.service.ts file.

    • getUser : Returns promise to load the User object for the currently authenticated user.
    • removeUser : Returns promise to remove from any storage the currently authenticated user.
    • signinRedirect : Returns promise to trigger a redirect of the current window to the authorization endpoint.
    • signinRedirectCallback : Returns promise to process response from the authorization endpoint. The result of the promise is the authenticated User.
    • signinSilent : Returns promise to trigger a silent request (via an iframe) to the authorization endpoint. The result of the promise is the authenticated User.
    • signinSilentCallback : Returns promise to notify the parent window of response from the authorization endpoint.
    • signoutRedirect : Returns promise to trigger a redirect of the current window to the end session endpoint.
    • signoutRedirectCallback : Returns promise to process response from the end session endpoint.

    Step 7: Create authgard service

    Create authgard service which help to automatically redirect to logged in page if user is not authenticate.

    import { Injectable } from '@angular/core';
    import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
    import { AuthService } from './auth.service';
    
    @Injectable()
    export class AuthGuard implements CanActivate {
    
      constructor(private router: Router, private authService: AuthService) { 
    
      }
    
      canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
        if (this.authService.isAuthenticated()) { return true; }
        this.authService.login();
        return false;
      
      }

    Step 8: Create AuthCall back component

    Create auth call back component which will be redirect url of after successfully logged in to identity server. Below is content of the auth-callback.ts component

    import { Component, OnInit } from "@angular/core";
    import { Router } from "@angular/router";
    import { AuthService } from "../core/authentication/auth.service";
    
    @Component({
      selector: "app-auth-callback",
      templateUrl: "./auth-callback.component.html",
      styleUrls: ["./auth-callback.component.scss"]
    })
    export class AuthCallbackComponent implements OnInit {
      error: boolean;
    
      constructor(
        private authService: AuthService,
        private router: Router
      ) { }
    
      async ngOnInit() {
        await this.authService.completeAuthentication();
        this.router.navigate(["/home"]);     
      }
    }

    Step 9: Create Home Component

    Create Home component which will display after successfully logged in. It is simple component and its routing configuration set to canActive so if user directly use the home link and not authorize then redirect to login page.

    Step 10: Create Logout component

    Create logout component which we will use when user logout from angular App and we need to redirect to identity server logout screen. Below is code for logout component

    import { Component, OnInit } from '@angular/core';
    import { AuthService } from '../core/authentication/auth.service';
    
    @Component({
      selector: 'app-logout',
      templateUrl: './logout.component.html',
      styleUrls: ['./logout.component.sass']
    })
    export class LogoutComponent implements OnInit {
    
      constructor(private authService: AuthService) { 
        this.authService.signout();
      }
    
      ngOnInit() {
      } 
    }