Using OpenIdConnect with Azure AD, Angular5 and WebAPI Core: Angular5 configuration
- Using OpenIdConnect with Azure AD, Angular5 and WebAPI Core: Introduction
- Using OpenIdConnect with Azure AD, Angular5 and WebAPI Core: Azure AD configuration
- Using OpenIdConnect with Azure AD, Angular5 and WebAPI Core: Angular5 configuration
- Using OpenIdConnect with Azure AD, Angular5 and WebAPI Core: WebAPI configuration
- Using OpenIdConnect with Azure AD, Angular5 and WebAPI Core: Token lifetime management
Install required packages and setup Angular 5 application
Firstly install the latest version of Angular with Angular-CLI
npm install -g @angular/cli
Then install an angular version of ADAL.JS: adal-angular5
npm install --save adal-angular5
Create a AuthService
We will create a AuthService.ts, this service will manage signin, signout and users data :
auth.service.ts:
import { Adal5HTTPService, Adal5Service } from 'adal-angular5'; import { HttpClient, HttpHandler } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; @Injectable() export class AuthService { private_user=null; private_config = { tenant:'136544d9-038e-4646-afff-10accb370679', <-- tenantId mentionned in the previous article clientId:'257b6c36-1168-4aac-be93-6f2cd81cec43', <-- clientId mentionned in the previous article redirectUri:"http://localhost:4200/auth-callback", <-- callback URI mentionned in the previous article postLogoutRedirectUri:"http://localhost:4200" <-- same URI as homepage URI mentionned in the previous article } constructor(private_adal:Adal5Service) { this._adal.init(this._config); } public isLoggedIn():boolean { return this._adal.userInfo.authenticated; } public signout():void { this._adal.logOut(); } public startAuthentication():any { this._adal.login(); } public getName():string { return this._user.profile.name; } public completeAuthentication():void { this._adal.handleWindowCallback(); this._adal.getUser().subscribe(user=> { this._user=user; console.log(this._adal.userInfo); var expireIn=user.profile.exp-newDate().getTime(); }); } }
this service is the most important thing, it will be used everywhere in the application.
Create a AuthGuardService
This AuthGuard service is usefull for protecting your page with authentication
You need to implement CanActivate method using Interface with the same name:
auth-guard.service.ts:
import { AuthService } from './auth.service'; import { Injectable } from '@angular/core'; import { CanActivate } from '@angular/router'; @Injectable() export class AuthGuardService implements CanActivate { constructor(private_authService:AuthService) { } canActivate():boolean { if(this._authService.isLoggedIn()) { return true; } this._authService.startAuthentication(); return false; } }
CanActivate is fired when you try to access to a route that is protected.
To setup route protection, create a component served by a protected route you want to protected with authentication, and setup route protection in app.module.ts:
Example of a protected component:
protected.component.ts:
import { AuthService } from './../services/auth.service'; import { Component, OnInit } from '@angular/core'; @Component({ selector:'app-protected', templateUrl:'./protected.component.html', styleUrls: ['./protected.component.css'] }) export class ProtectedComponent implements OnInit { name:String=""; constructor(private_authService:AuthService) { } ngOnInit() { this.name=this._authService.getName(); } public signout():void { this._authService.signout(); } }
protected.component.html:
<p> Welcome {{name}} </p> <a href="javascript:void(0);" (click)="signout();">signout</a>
Protect your routes like this in app.module.ts:
const routes: Routes = [ { path:'', children: [] }, { path:'protected', component:ProtectedComponent, canActivate: [AuthGuardService] }, { path:'auth-callback', component:AuthCallbackComponent } ];
Create a AuthCallback component
This component will be used as endpoint in your app to manage user creation after receiving the token from Azure Authorization endpoint.
Azure AD will call your page and send the token. If you remember well, the URI has to be declaqred in Azure to make it work.
auth-callback.component.ts:
import { AuthService } from './../services/auth.service'; import { Router, ActivatedRoute } from '@angular/router'; import { Component, OnInit, NgZone } from '@angular/core'; @Component({ selector:'app-auth-callback', templateUrl:'./auth-callback.component.html', styleUrls: ['./auth-callback.component.css'] }) export class AuthCallbackComponent implements OnInit { constructor(private_router:Router, private_authService:AuthService, private_zone:NgZone, private_activatedRoute:ActivatedRoute) { } ngOnInit() { this._authService.completeAuthentication(); setTimeout(() => {this._zone.run( () => this._router.navigate(['/protected']) );},200); } }
auth-callback.component.html:
<p>Please wait while we redirect you back</p>
The method completeAuthentication is in fact internally a Promise but I execute the redirection after authentication synchronously by using a setTimeout statement.
I used also NgZone object.
Why this?
Passing a callback to promise after authentication in completeAuthentication did not work on Safari IOS, so the work around was using setTimeout inside NgZone… a bit dirty but it works! 🙂
Modify you app.component.html to test a protected route:
<h3><a routerLink="/">Home</a> | <a routerLink="/protected">Protected</a></h3> <h1> {{title}} </h1> <router-outlet></router-outlet>
Check your app.module.ts
Your app.module.ts should be well setup like this:
import { AuthService } from './services/auth.service'; import { AuthGuardService } from './services/auth-guard.service'; import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; import { ProtectedComponent } from './protected/protected.component'; import { AuthCallbackComponent } from './auth-callback/auth-callback.component'; import { Adal5Service, Adal5HTTPService } from 'adal-angular5'; import { HttpClient } from '@angular/common/http'; const routes: Routes = [ { path:'', children: [] }, { path:'protected', component:ProtectedComponent, canActivate: [AuthGuardService] }, { path:'auth-callback', component:AuthCallbackComponent } ]; @NgModule({ declarations: [ AppComponent, ProtectedComponent, AuthCallbackComponent ], imports: [ BrowserModule, RouterModule.forRoot(routes) ], exports: [RouterModule], providers: [AuthGuardService, AuthService, Adal5Service,{ provide:Adal5HTTPService, useFactory:Adal5HTTPService.factory, deps: [HttpClient, Adal5Service] } ], bootstrap: [AppComponent] }) export class AppModule { }
Demo time !!!
If everything is well setup in Azure and in your Angular 5 application, if you try to go to navigate to a protected route you should have a logging page to Microsoft and be redirected to your web application:
If log in your browser console the authenticated user object you should have something like this :
Awesome right ? 😉
Now let’s see how we protect a Web Api: Using OpenIdConnect with Azure AD, Angular5 and WebAPI Core: WebAPI configuration