Harun
Harun

Reputation: 5179

Angular4 azure active directory authentication using ng2-adal library fails when used with hash location strategy

Angular4 azure active directory authentication using ng2-adal library removes id_token from the url.

I referred the following blog for the implementation. https://dotronald.be/add-azure-active-directory-to-an-existing-angular-2-single-page-application/

  1. Installed ng4-adal

  2. Created a typescript config file for ng4-adal to set azure connection details as follows, import {Injectable} from '@angular/core';

            @Injectable()
           export class AdalConfig {
                  public get getAdalConfig(): any {
                  return {
                      tenant: 'YOUR TENANT NAME',
                      clientId: 'YOUR CLIENT ID',           
                      redirectUri: window.location.origin + '/',
                       postLogoutRedirectUri: window.location.origin + 
                      '/logout'
                };
                }
             }
    
  3. Created a canActivate guard that authenticates the angular routes before navigation as follows,

             import { Injectable } from '@angular/core';
             import { Router, CanActivate,   
             ActivatedRouteSnapshot,RouterStateSnapshot, NavigationExtras } 
             from '@angular/router';
             import {AdalService} from "ng4-adal/core";
    
             @Injectable()
             export class AuthenticationGuard implements CanActivate {
    
             constructor(private _adalService: AdalService, private router: 
             Router) { }
    
             canActivate(route: ActivatedRouteSnapshot, state: 
             RouterStateSnapshot): boolean{
    
                if (this._adalService.userInfo.isAuthenticated) {
                    return true;
                }
                else {
                        this._adalService.login();
                        return false;
                }   }  }
    
  4. Added the following code in the constructor of the app.component.ts to initiate the ng4-adal service as follows,

                constructor(
                     private _adalService: AdalService,
                     private _adalConfigService: AdalConfig
               )                 
         {this._adalService.init(this._adalConfigService.getAdalConfig);}
    
  5. To prevent the user having to log in every time again, the authentication token is stored in the browser cache. This allows us to try to retrieve this token and continue using the application without being redirected again to the Azure login page.

Added the following code in the ngOninit of the app.component.ts to overcome the above issue as follows,

              ngOnInit() {
                 this._adalService.handleWindowCallback();
                 this._adalService.getUser();
              }
  1. Set the guard created in step 3 for required routes in the app-routing.ts file as follows,

            const routes: Routes = [
            { path: '', redirectTo: '/home', pathMatch: 'full', canActivate: 
             [AuthenticationGuard]},
             { path: 'admin-measure', redirectTo: '/#admin-measure'},
             { path: 'home', component: HomeComponent, canActivate: 
               [AuthenticationGuard] },                 
             { path: 'logout', component: LogoutComponent },
             { path: 'unauthorized', component: UnauthorizedComponent }
           ];
    
  2. Registered the services in app.module.

The error i'm getting in console follows, ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'id_token'

Problem found by research: There's an issue with redirects when using hashes in Angular 2. The problem is that when the authResult comes back in the redirect after authentication, Angular thinks it's a route called access_token.

Any solution for this?

Upvotes: 2

Views: 1827

Answers (1)

Harun
Harun

Reputation: 5179

I found the solution.

The callback from the Service Provider is using #/id_token which Angular2 router cannot understand. Will get an error in console – “Error: Cannot match any routes. Url Segment: ‘id_token’”. To address this, we will add a callback route to digest the JWT Token then redirect to our destination page.

a. Create oauth-callback.component as follows,

        import { Component, OnInit } from '@angular/core';
        import { Router } from '@angular/router';
        import {AdalService} from "ng4-adal/core";

        @Component({
                template: '<div>Please wait...</div>'
        })

        export class OAuthCallbackComponent implements OnInit {

        constructor(private router: Router, private _adalService: 
        AdalService) {}

        ngOnInit() {
                if (!this._adalService.userInfo) {
                    this._adalService.login();
                } else {
                    this.router.navigate(['home']);
               }
              }
        }

b. Create an oauth-callback-handler.guard for the “id_token” route as follows,

        import { Injectable } from '@angular/core';
        import { Router, CanActivate, ActivatedRouteSnapshot, 
        RouterStateSnapshot } from '@angular/router';
        import { AdalService } from 'ng4-adal/core';

        @Injectable()
        export class OAuthCallbackHandlerGuard implements CanActivate {

        constructor(private router: Router, private _adalService: 
        AdalService) { }

        canActivate(route: ActivatedRouteSnapshot, state: 
        RouterStateSnapshot): boolean {

            this._adalService.handleWindowCallback();

            if (this._adalService.userInfo.isAuthenticated) {

                var returnUrl = route.queryParams['returnUrl'];
                if (!returnUrl) {
                    this.router.navigate(['home']);
                } else {
                    this.router.navigate([returnUrl], { queryParams: 
                    route.queryParams });
                }
            }
            else {
                    this._adalService.login();
            }

            return false;
            }
         }

c. Register the oauth-callback.component and oauth-callback-handler.guard in app.module.

d. Register the route for “id_token” to be handled by oauth-callback.component and oauth-callback-handler.guard as follows,

          const routes: Routes = [
         { path: 'id_token', component: OAuthCallbackComponent, canActivate: 
           [OAuthCallbackHandlerGuard] }[AuthenticationGuard]},              
         { path: 'logout', component: LogoutComponent }];       

For further reference please see the below link,

https://blogs.msdn.microsoft.com/premier_developer/2017/04/26/using-adal-with-angular2/

Upvotes: 5

Related Questions