Azure AD Integration With Angular And ASP.NET Core Web API

Introduction

This blog is going to showcase to you how we can implement Azure AD with web API and Angular application.

Azure AD Integration with Angular and ASP.NET Core Web API

To connect azure ad with angular and asp.net core web API 5.0.

There are four-step processes to implement Azure AD in angular and asp.net core web API.

Step 1

Create Azure AD Account and Register the SPA(Single Page Application ) application in Azure AD App Registration blade.

Azure AD Integration with Angular and ASP.NET Core Web API

Azure AD Integration with Angular and ASP.NET Core Web API

First, click on the App Registration button and then click on New Registration Button.

Azure AD Integration with Angular and ASP.NET Core Web API

Fill in the Register Application Details.

Azure AD Integration with Angular and ASP.NET Core Web API

Azure AD Integration with Angular and ASP.NET Core Web API

After clicking on the Register button. SPA application successfully gets registered and on the overview page, you get the register application details like Client ID, Tenant ID, etc.

Azure AD Integration with Angular and ASP.NET Core Web API

Step 2

Register Web API applications in the same way. But in the API registration process, we do not need to provide the application redirect URL because our SPA Application is used to redirect the page.

Azure AD Integration with Angular and ASP.NET Core Web API

Azure AD Integration with Angular and ASP.NET Core Web API

Then need to Expose An API,

Azure AD Integration with Angular and ASP.NET Core Web API

Azure AD Integration with Angular and ASP.NET Core Web API

After successfully exposing the API and scope has been added you need to go into the SPA application and add the permission for this API. Follow the process and click as per the number in below pic.

Azure AD Integration with Angular and ASP.NET Core Web API

Step 3

Go to VS Code and Create New application in Angular, do the below changes. Add the below packages and do the npm install.

Azure AD Integration with Angular and ASP.NET Core Web API

Add Auth-Config File and do the below settings as per the SPA application Registered.

Azure AD Integration with Angular and ASP.NET Core Web API

Add below setting in App.Module.ts,

import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { TodoEditComponent } from './todo-edit/todo-edit.component';
import { TodoViewComponent } from './todo-view/todo-view.component';
import { TodoService } from './todo.service';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { IPublicClientApplication, PublicClientApplication, InteractionType } from '@azure/msal-browser';
import { MsalGuard, MsalInterceptor, MsalBroadcastService, MsalInterceptorConfiguration, MsalModule, MsalService, MSAL_GUARD_CONFIG, MSAL_INSTANCE, MSAL_INTERCEPTOR_CONFIG, MsalGuardConfiguration, MsalRedirectComponent } from '@azure/msal-angular'; 
import { msalConfig, loginRequest, protectedResources } from './auth-config';
export function MSALInstanceFactory(): IPublicClientApplication {
    return new PublicClientApplication(msalConfig);
}
export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
    const protectedResourceMap = new Map < string,
        Array < string >> ();
    protectedResourceMap.set(protectedResources.todoListApi.endpoint, protectedResources.todoListApi.scopes);
    return {
        interactionType: InteractionType.Redirect,
        protectedResourceMap
    };
}
export function MSALGuardConfigFactory(): MsalGuardConfiguration {
    return {
        interactionType: InteractionType.Redirect,
        authRequest: loginRequest
    };
}
@NgModule({
    declarations: [
        AppComponent,
        HomeComponent,
        TodoViewComponent,
        TodoEditComponent
    ],
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        HttpClientModule,
        FormsModule,
        MsalModule
    ],
    providers: [{
            provide: HTTP_INTERCEPTORS,
            useClass: MsalInterceptor,
            multi: true
        }, {
            provide: MSAL_INSTANCE,
            useFactory: MSALInstanceFactory
        }, {
            provide: MSAL_GUARD_CONFIG,
            useFactory: MSALGuardConfigFactory
        }, {
            provide: MSAL_INTERCEPTOR_CONFIG,
            useFactory: MSALInterceptorConfigFactory
        },
        MsalService,
        MsalGuard,
        MsalBroadcastService,
        TodoService
    ],
    bootstrap: [AppComponent, MsalRedirectComponent]
})
export class AppModule {}

App.Component Settings,

import { Component, OnInit, Inject, OnDestroy } from '@angular/core';
import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
import { AuthenticationResult, InteractionStatus, InteractionType, PopupRequest, RedirectRequest } from '@azure/msal-browser';
import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
    title = 'Azure Ad Testing Demo';
    isIframe = false;
    loginDisplay = false;
    private readonly _destroying$ = new Subject < void > ();
    constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private authService: MsalService, private msalBroadcastService: MsalBroadcastService) {}
    ngOnInit(): void {
        this.isIframe = window !== window.parent && !window.opener;
        /**
         * You can subscribe to MSAL events as shown below. For more info,
         * visit: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/v2-docs/events.md
         */
        this.msalBroadcastService.inProgress$.pipe(filter((status: InteractionStatus) => status === InteractionStatus.None), takeUntil(this._destroying$)).subscribe(() => {
            this.setLoginDisplay();
        });
    }
    setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
    }
    login() {
        if (this.msalGuardConfig.interactionType === InteractionType.Popup) {
            if (this.msalGuardConfig.authRequest) {
                this.authService.loginPopup({
                        ...this.msalGuardConfig.authRequest
                    }
                    as PopupRequest).subscribe((response: AuthenticationResult) => {
                    this.authService.instance.setActiveAccount(response.account);
                });
            } else {
                this.authService.loginPopup().subscribe((response: AuthenticationResult) => {
                    this.authService.instance.setActiveAccount(response.account);
                });
            }
        } else {
            if (this.msalGuardConfig.authRequest) {
                this.authService.loginRedirect({
                        ...this.msalGuardConfig.authRequest
                    }
                    as RedirectRequest);
            } else {
                this.authService.loginRedirect();
            }
        }
    }
    logout() {
        this.authService.logout();
    }
    // unsubscribe to events when component is destroyed
    ngOnDestroy(): void {
        this._destroying$.next(undefined);
        this._destroying$.complete();
    }
}

app.component.html settings,

<mat-toolbar color="primary">
  <a class="title" href="/">{{ title }}</a>
  <div class="toolbar-spacer"></div>
  <a mat-button [routerLink]="['todo-view']">TodoList</a>
  <button mat-raised-button *ngIf="!loginDisplay" (click)="login()">Login</button>
  <button mat-raised-button color="accent" *ngIf="loginDisplay" (click)="logout()">Logout</button>
</mat-toolbar>
<div class="container">
  <!--This is to avoid reload during acquireTokenSilent() because of hidden iframe -->
  <router-outlet *ngIf="!isIframe"></router-outlet>
</div>
<footer *ngIf="loginDisplay">
  <mat-toolbar>
    <div class="footer-text"> How did we do? </div>
  </mat-toolbar>
</footer>

Index.html settings,

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>AzureDemoSPA</title>
    <base href="/">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" type="image/x-icon" href="favicon.svg">
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  </head>
  <body>
    <app-root></app-root>
    <app-redirect></app-redirect>
  </body>
</html>

Step 4 - Web API settings

In AppSettings.json file add your Registered API tenant and Client ID and Domain name information.

Azure AD Integration with Angular and ASP.NET Core Web API

From Nuget Package manager add microsoft.identity.web package and do the changes in startup’s file.

using AzureAdAPIDemo.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Identity.Web;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AzureAdAPIDemo {
    public class Startup {
        public Startup(IConfiguration configuration) {
            Configuration = configuration;
        }
        public IConfiguration Configuration {
            get;
        }
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services) {
            // Setting configuration for protected web api
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApi(Configuration);
            // Creating policies that wraps the authorization requirements
            services.AddAuthorization();
            services.AddDbContext < TodoContext > (opt => opt.UseInMemoryDatabase("TodoList"));
            services.AddControllers();
            // Allowing CORS for all domains and methods for the purpose of the sample
            // In production, modify this with the actual domains you want to allow
            services.AddCors(o => o.AddPolicy("default", builder => {
                builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
            }));
            services.AddSwaggerGen(c => {
                c.SwaggerDoc("v1", new OpenApiInfo {
                    Title = "AzureAdAPIDemo", Version = "v1"
                });
            });
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
            if (env.IsDevelopment()) {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "AzureAdAPIDemo v1"));
            }
            app.UseCors("default");
            app.UseHttpsRedirection();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints => {
                endpoints.MapControllers();
            });
        }
    }
}

Then use [Authorize ] on any controller.

Azure AD Integration with Angular and ASP.NET Core Web API

Azure AD Integration with Angular and ASP.NET Core Web API

After clicking the login button,

Azure AD Integration with Angular and ASP.NET Core Web API

Select the account and log in successfully.

Azure AD Integration with Angular and ASP.NET Core Web API

Summary 

Follow the above steps and secure your solutions.