This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Download Microsoft Edge
More info about Internet Explorer and Microsoft Edge
In this tutorial, you build an Angular single-page application (SPA) that signs in users and calls the Microsoft Graph API by using the authorization code flow with PKCE. The SPA you build uses the Microsoft Authentication Library (MSAL) for Angular v2.
In this tutorial:
Create an Angular project with
npm
Register the application in the Azure portal
Add code to support user sign-in and sign-out
Add code to call Microsoft Graph API
Test the app
MSAL Angular v2 improves on MSAL Angular v1 by supporting the authorization code flow in the browser instead of the implicit grant flow. MSAL Angular v2 does
NOT
support the implicit flow.
Prerequisites
Node.js
for running a local web server.
Visual Studio Code
or other editor for modifying project files.
How the sample app works
The sample application created in this tutorial enables an Angular SPA to query the Microsoft Graph API or a web API that accepts tokens issued by the Microsoft identity platform. It uses the Microsoft Authentication Library (MSAL) for Angular v2, a wrapper of the MSAL.js v2 library. MSAL Angular enables Angular 9+ applications to authenticate enterprise users by using Azure Active Directory (Azure AD), and also users with Microsoft accounts and social identities like Facebook, Google, and LinkedIn. The library also enables applications to get access to Microsoft cloud services and Microsoft Graph.
In this scenario, after a user signs in, an access token is requested and added to HTTP requests through the authorization header. Token acquisition and renewal are handled by MSAL.
Libraries
This tutorial uses the following libraries:
Library
Description
You can find the source code for all of the MSAL.js libraries in the
AzureAD/microsoft-authentication-library-for-js
repository on GitHub.
Create your project
Once you have
Node.js
installed, open up a terminal window and then run the following commands to generate a new Angular application:
npm install -g @angular/cli # Install the Angular CLI
ng new msal-angular-tutorial --routing=true --style=css --strict=false # Generate a new Angular app
cd msal-angular-tutorial # Change to the app directory
npm install @angular/material @angular/cdk # Install the Angular Material component library (optional, for UI)
npm install @azure/msal-browser @azure/msal-angular # Install MSAL Browser and MSAL Angular in your application
ng generate component home # To add a home page
ng generate component profile # To add a profile page
Register your application
Follow the instructions to register a single-page application in the Azure portal.
On the app Overview page of your registration, note the Application (client) ID value for later use.
Register your Redirect URI value as http://localhost:4200/ and type as 'SPA'.
In the src/app folder, edit app.module.ts and add MsalModule
and MsalInterceptor
to imports
as well as the isIE
constant. Your code should look like this:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';
import { MsalModule } from '@azure/msal-angular';
import { PublicClientApplication } from '@azure/msal-browser';
const isIE = window.navigator.userAgent.indexOf('MSIE ') > -1 || window.navigator.userAgent.indexOf('Trident/') > -1;
@NgModule({
declarations: [
AppComponent,
HomeComponent,
ProfileComponent
imports: [
BrowserModule,
AppRoutingModule,
MsalModule.forRoot( new PublicClientApplication({
auth: {
clientId: 'Enter_the_Application_Id_here', // Application (client) ID from the app registration
authority: 'Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here', // The Azure cloud instance and the app's sign-in audience (tenant ID, common, organizations, or consumers)
redirectUri: 'Enter_the_Redirect_Uri_Here'// This is your redirect URI
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: isIE, // Set to true for Internet Explorer 11
}), null, null)
providers: [],
bootstrap: [AppComponent]
export class AppModule { }
Replace these values:
Value name
About
Enter_the_Application_Id_Here
On the Overview page of your application registration, this is your Application (client) ID value.
Enter_the_Cloud_Instance_Id_Here
This is the instance of the Azure cloud. For the main or global Azure cloud, enter https://login.microsoftonline.com. For national clouds (for example, China), see National clouds.
Enter_the_Tenant_Info_Here
Set to one of the following options: If your application supports accounts in this organizational directory, replace this value with the directory (tenant) ID or tenant name (for example, contoso.microsoft.com). If your application supports accounts in any organizational directory, replace this value with organizations. If your application supports accounts in any organizational directory and personal Microsoft accounts, replace this value with common. To restrict support to personal Microsoft accounts only, replace this value with consumers.
Enter_the_Redirect_Uri_Here
Replace with http://localhost:4200.
For more information about available configurable options, see Initialize client applications.
Add routes to the home and profile components in the src/app/app-routing.module.ts. Your code should look like the following:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { BrowserUtils } from '@azure/msal-browser';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';
const routes: Routes = [
path: 'profile',
component: ProfileComponent,
path: '',
component: HomeComponent
const isIframe = window !== window.parent && !window.opener;
@NgModule({
imports: [RouterModule.forRoot(routes, {
// Don't perform initial navigation in iframes or popups
initialNavigation: !BrowserUtils.isInIframe() && !BrowserUtils.isInPopup() ? 'enabledNonBlocking' : 'disabled' // Set to enabledBlocking to use Angular Universal
exports: [RouterModule]
export class AppRoutingModule { }
Replace base UI
Replace the placeholder code in src/app/app.component.html with the following:
<mat-toolbar color="primary">
<a class="title" href="/">{{ title }}</a>
<div class="toolbar-spacer"></div>
<a mat-button [routerLink]="['profile']">Profile</a>
<button mat-raised-button *ngIf="!loginDisplay" (click)="login()">Login</button>
</mat-toolbar>
<div class="container">
<!--This is to avoid reload during acquireTokenSilent() because of hidden iframe -->
<router-outlet *ngIf="!isIframe"></router-outlet>
Add material modules to src/app/app.module.ts. Your AppModule
should look like this:
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatListModule } from '@angular/material/list';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';
import { MsalModule } from '@azure/msal-angular';
import { PublicClientApplication } from '@azure/msal-browser';
const isIE = window.navigator.userAgent.indexOf('MSIE ') > -1 || window.navigator.userAgent.indexOf('Trident/') > -1;
@NgModule({
declarations: [
AppComponent,
HomeComponent,
ProfileComponent
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
MatButtonModule,
MatToolbarModule,
MatListModule,
MsalModule.forRoot( new PublicClientApplication({
auth: {
clientId: 'Enter_the_Application_Id_here',
authority: 'Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here',
redirectUri: 'Enter_the_Redirect_Uri_Here'
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: isIE,
}), null, null)
providers: [],
bootstrap: [AppComponent]
export class AppModule { }
(OPTIONAL) Add CSS to src/style.css:
@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
.container { margin: 1%; }
(OPTIONAL) Add CSS to src/app/app.component.css:
.toolbar-spacer {
flex: 1 1 auto;
a.title {
color: white;
Sign in a user
Add the code from the following sections to invoke login using a pop-up window or a full-frame redirect:
Sign in using pop-ups
Change the code in src/app/app.component.ts to the following to sign in a user using a pop-up window:
import { MsalService } from '@azure/msal-angular';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
export class AppComponent implements OnInit {
title = 'msal-angular-tutorial';
isIframe = false;
loginDisplay = false;
constructor(private authService: MsalService) { }
ngOnInit() {
this.isIframe = window !== window.parent && !window.opener;
login() {
this.authService.loginPopup()
.subscribe({
next: (result) => {
console.log(result);
this.setLoginDisplay();
error: (error) => console.log(error)
setLoginDisplay() {
this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
The rest of this tutorial uses the loginRedirect
method with Microsoft Internet Explorer because of a known issue related to the handling of pop-up windows by Internet Explorer.
Sign in using redirects
Update src/app/app.module.ts to bootstrap the MsalRedirectComponent
. This is a dedicated redirect component which will handle redirects. Your code should now look like this:
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatListModule } from '@angular/material/list';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';
import { MsalModule, MsalRedirectComponent } from '@azure/msal-angular'; // Updated import
import { PublicClientApplication } from '@azure/msal-browser';
const isIE = window.navigator.userAgent.indexOf('MSIE ') > -1 || window.navigator.userAgent.indexOf('Trident/') > -1;
@NgModule({
declarations: [
AppComponent,
HomeComponent,
ProfileComponent
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
MatButtonModule,
MatToolbarModule,
MatListModule,
MsalModule.forRoot( new PublicClientApplication({
auth: {
clientId: 'Enter_the_Application_Id_here',
authority: 'Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here',
redirectUri: 'Enter_the_Redirect_Uri_Here'
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: isIE,
}), null, null)
providers: [],
bootstrap: [AppComponent, MsalRedirectComponent] // MsalRedirectComponent bootstrapped here
export class AppModule { }
Add the <app-redirect>
selector to src/index.html. This selector is used by the MsalRedirectComponent
. Your src/index.html should look like this:
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>msal-angular-tutorial</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<app-root></app-root>
<app-redirect></app-redirect>
</body>
</html>
Replace the code in src/app/app.component.ts with the following to sign in a user using a full-frame redirect:
import { MsalService } from '@azure/msal-angular';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
export class AppComponent implements OnInit {
title = 'msal-angular-tutorial';
isIframe = false;
loginDisplay = false;
constructor(private authService: MsalService) { }
ngOnInit() {
this.isIframe = window !== window.parent && !window.opener;
login() {
this.authService.loginRedirect();
setLoginDisplay() {
this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
Replace existing code in src/app/home/home.component.ts to subscribe to the LOGIN_SUCCESS
event. This will allow you to access the result from the successful login with redirect. Your code should look like this:
import { Component, OnInit } from '@angular/core';
import { MsalBroadcastService, MsalService } from '@azure/msal-angular';
import { EventMessage, EventType, InteractionStatus } from '@azure/msal-browser';
import { filter } from 'rxjs/operators';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
export class HomeComponent implements OnInit {
constructor(private authService: MsalService, private msalBroadcastService: MsalBroadcastService) { }
ngOnInit(): void {
this.msalBroadcastService.msalSubject$
.pipe(
filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS),
.subscribe((result: EventMessage) => {
console.log(result);
Conditional rendering
In order to render certain UI only for authenticated users, components have to subscribe to the MsalBroadcastService
to see if users have been signed in and interaction has completed.
Add the MsalBroadcastService
to src/app/app.component.ts and subscribe to the inProgress$
observable to check if interaction is complete and an account is signed in before rendering UI. Your code should now look like this:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { MsalService, MsalBroadcastService } from '@azure/msal-angular';
import { InteractionStatus } 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 = 'msal-angular-tutorial';
isIframe = false;
loginDisplay = false;
private readonly _destroying$ = new Subject<void>();
constructor(private broadcastService: MsalBroadcastService, private authService: MsalService) { }
ngOnInit() {
this.isIframe = window !== window.parent && !window.opener;
this.broadcastService.inProgress$
.pipe(
filter((status: InteractionStatus) => status === InteractionStatus.None),
takeUntil(this._destroying$)
.subscribe(() => {
this.setLoginDisplay();
login() {
this.authService.loginRedirect();
setLoginDisplay() {
this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
ngOnDestroy(): void {
this._destroying$.next(undefined);
this._destroying$.complete();
Update the code in src/app/home/home.component.ts to also check for interaction to be completed before updating UI. Your code should now look like this:
import { Component, OnInit } from '@angular/core';
import { MsalBroadcastService, MsalService } from '@azure/msal-angular';
import { EventMessage, EventType, InteractionStatus } from '@azure/msal-browser';
import { filter } from 'rxjs/operators';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
export class HomeComponent implements OnInit {
loginDisplay = false;
constructor(private authService: MsalService, private msalBroadcastService: MsalBroadcastService) { }
ngOnInit(): void {
this.msalBroadcastService.msalSubject$
.pipe(
filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS),
.subscribe((result: EventMessage) => {
console.log(result);
this.msalBroadcastService.inProgress$
.pipe(
filter((status: InteractionStatus) => status === InteractionStatus.None)
.subscribe(() => {
this.setLoginDisplay();
setLoginDisplay() {
this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
Replace the code in src/app/home/home.component.html with the following conditional displays:
<div *ngIf="!loginDisplay">
<p>Please sign-in to see your profile information.</p>
<div *ngIf="loginDisplay">
<p>Login successful!</p>
<p>Request your profile information by clicking Profile above.</p>
Guarding routes
Angular Guard
MSAL Angular provides MsalGuard
, a class you can use to protect routes and require authentication before accessing the protected route. The steps below add the MsalGuard
to the Profile
route. Protecting the Profile
route means that even if a user does not sign in using the Login
button, if they try to access the Profile
route or click the Profile
button, the MsalGuard
will prompt the user to authenticate via pop-up or redirect before showing the Profile
page.
MsalGuard
is a convenience class you can use improve the user experience, but it should not be relied upon for security. Attackers can potentially get around client-side guards, and you should ensure that the server does not return any data the user should not access.
Add the MsalGuard
class as a provider in your application in src/app/app.module.ts, and add the configurations for the MsalGuard
. Scopes needed for acquiring tokens later can be provided in the authRequest
, and the type of interaction for the Guard can be set to Redirect
or Popup
. Your code should look like the following:
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatListModule } from '@angular/material/list';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';
import { MsalModule, MsalRedirectComponent, MsalGuard } from '@azure/msal-angular'; // MsalGuard added to imports
import { PublicClientApplication, InteractionType } from '@azure/msal-browser'; // InteractionType added to imports
const isIE = window.navigator.userAgent.indexOf('MSIE ') > -1 || window.navigator.userAgent.indexOf('Trident/') > -1;
@NgModule({
declarations: [
AppComponent,
HomeComponent,
ProfileComponent
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
MatButtonModule,
MatToolbarModule,
MatListModule,
MsalModule.forRoot( new PublicClientApplication({
auth: {
clientId: 'Enter_the_Application_Id_here',
authority: 'Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here',
redirectUri: 'Enter_the_Redirect_Uri_Here'
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: isIE,
}), {
interactionType: InteractionType.Redirect, // MSAL Guard Configuration
authRequest: {
scopes: ['user.read']
}, null)
providers: [
MsalGuard // MsalGuard added as provider here
bootstrap: [AppComponent, MsalRedirectComponent]
export class AppModule { }
Set the MsalGuard
on the routes you wish to protect in src/app/app-routing.module.ts:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';
import { MsalGuard } from '@azure/msal-angular';
const routes: Routes = [
path: 'profile',
component: ProfileComponent,
canActivate: [MsalGuard]
path: '',
component: HomeComponent
const isIframe = window !== window.parent && !window.opener;
@NgModule({
imports: [RouterModule.forRoot(routes, {
initialNavigation: !isIframe ? 'enabled' : 'disabled' // Don't perform initial navigation in iframes
exports: [RouterModule]
export class AppRoutingModule { }
Adjust the login calls in src/app/app.component.ts to take the authRequest
set in the guard configurations into account. Your code should now look like the following:
import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
import { InteractionStatus, 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 = 'msal-angular-tutorial';
isIframe = false;
loginDisplay = false;
private readonly _destroying$ = new Subject<void>();
constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private broadcastService: MsalBroadcastService, private authService: MsalService) { }
ngOnInit() {
this.isIframe = window !== window.parent && !window.opener;
this.broadcastService.inProgress$
.pipe(
filter((status: InteractionStatus) => status === InteractionStatus.None),
takeUntil(this._destroying$)
.subscribe(() => {
this.setLoginDisplay();
login() {
if (this.msalGuardConfig.authRequest){
this.authService.loginRedirect({...this.msalGuardConfig.authRequest} as RedirectRequest);
} else {
this.authService.loginRedirect();
setLoginDisplay() {
this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
ngOnDestroy(): void {
this._destroying$.next(undefined);
this._destroying$.complete();
Acquire a token
Angular Interceptor
MSAL Angular provides an Interceptor
class that automatically acquires tokens for outgoing requests that use the Angular http
client to known protected resources.
Add the Interceptor
class as a provider to your application in src/app/app.module.ts, with its configurations. Your code should now look like this:
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS, HttpClientModule } from "@angular/common/http"; // Import
import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatListModule } from '@angular/material/list';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';
import { MsalModule, MsalRedirectComponent, MsalGuard, MsalInterceptor } from '@azure/msal-angular'; // Import MsalInterceptor
import { InteractionType, PublicClientApplication } from '@azure/msal-browser';
const isIE = window.navigator.userAgent.indexOf('MSIE ') > -1 || window.navigator.userAgent.indexOf('Trident/') > -1;
@NgModule({
declarations: [
AppComponent,
HomeComponent,
ProfileComponent
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
MatButtonModule,
MatToolbarModule,
MatListModule,
HttpClientModule,
MsalModule.forRoot( new PublicClientApplication({
auth: {
clientId: 'Enter_the_Application_Id_Here',
authority: 'Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here',
redirectUri: 'Enter_the_Redirect_Uri_Here',
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: isIE,
}), {
interactionType: InteractionType.Redirect,
authRequest: {
scopes: ['user.read']
interactionType: InteractionType.Redirect, // MSAL Interceptor Configuration
protectedResourceMap: new Map([
['Enter_the_Graph_Endpoint_Here/v1.0/me', ['user.read']]
providers: [
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true
MsalGuard
bootstrap: [AppComponent, MsalRedirectComponent]
export class AppModule { }
The protected resources are provided as a protectedResourceMap
. The URLs you provide in the protectedResourceMap
collection are case-sensitive. For each resource, add scopes being requested to be returned in the access token.
For example:
["user.read"]
for Microsoft Graph
["<Application ID URL>/scope"]
for custom web APIs (that is, api://<Application ID>/access_as_user
)
Modify the values in the protectedResourceMap
as described here:
Value name
About
Enter_the_Graph_Endpoint_Here
The instance of the Microsoft Graph API the application should communicate with. For the global Microsoft Graph API endpoint, replace both instances of this string with https://graph.microsoft.com
. For endpoints in national cloud deployments, see National cloud deployments in the Microsoft Graph documentation.
Replace the code in src/app/profile/profile.component.ts to retrieve a user's profile with an HTTP request:
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
const GRAPH_ENDPOINT = 'Enter_the_Graph_Endpoint_Here/v1.0/me';
type ProfileType = {
givenName?: string,
surname?: string,
userPrincipalName?: string,
id?: string
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
export class ProfileComponent implements OnInit {
profile!: ProfileType;
constructor(
private http: HttpClient
) { }
ngOnInit() {
this.getProfile();
getProfile() {
this.http.get(GRAPH_ENDPOINT)
.subscribe(profile => {
this.profile = profile;
Replace the UI in src/app/profile/profile.component.html to display profile information:
<p><strong>First Name: </strong> {{profile?.givenName}}</p>
<p><strong>Last Name: </strong> {{profile?.surname}}</p>
<p><strong>Email: </strong> {{profile?.userPrincipalName}}</p>
<p><strong>Id: </strong> {{profile?.id}}</p>
Sign out
Update the code in src/app/app.component.html to conditionally display a Logout
button:
<mat-toolbar color="primary">
<a class="title" href="/">{{ title }}</a>
<div class="toolbar-spacer"></div>
<a mat-button [routerLink]="['profile']">Profile</a>
<button mat-raised-button *ngIf="!loginDisplay" (click)="login()">Login</button>
<button mat-raised-button *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>
Sign out using redirects
Update the code in src/app/app.component.ts to sign out a user using redirects:
import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
import { InteractionStatus, 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 = 'msal-angular-tutorial';
isIframe = false;
loginDisplay = false;
private readonly _destroying$ = new Subject<void>();
constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private broadcastService: MsalBroadcastService, private authService: MsalService) { }
ngOnInit() {
this.isIframe = window !== window.parent && !window.opener;
this.broadcastService.inProgress$
.pipe(
filter((status: InteractionStatus) => status === InteractionStatus.None),
takeUntil(this._destroying$)
.subscribe(() => {
this.setLoginDisplay();
login() {
if (this.msalGuardConfig.authRequest){
this.authService.loginRedirect({...this.msalGuardConfig.authRequest} as RedirectRequest);
} else {
this.authService.loginRedirect();
logout() { // Add log out function here
this.authService.logoutRedirect({
postLogoutRedirectUri: 'http://localhost:4200'
setLoginDisplay() {
this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
ngOnDestroy(): void {
this._destroying$.next(undefined);
this._destroying$.complete();
Sign out using pop-ups
Update the code in src/app/app.component.ts to sign out a user using pop-ups:
import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
import { InteractionStatus, PopupRequest } 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 = 'msal-angular-tutorial';
isIframe = false;
loginDisplay = false;
private readonly _destroying$ = new Subject<void>();
constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private broadcastService: MsalBroadcastService, private authService: MsalService) { }
ngOnInit() {
this.isIframe = window !== window.parent && !window.opener;
this.broadcastService.inProgress$
.pipe(
filter((status: InteractionStatus) => status === InteractionStatus.None),
takeUntil(this._destroying$)
.subscribe(() => {
this.setLoginDisplay();
login() {
if (this.msalGuardConfig.authRequest){
this.authService.loginPopup({...this.msalGuardConfig.authRequest} as PopupRequest)
.subscribe({
next: (result) => {
console.log(result);
this.setLoginDisplay();
error: (error) => console.log(error)
} else {
this.authService.loginPopup()
.subscribe({
next: (result) => {
console.log(result);
this.setLoginDisplay();
error: (error) => console.log(error)
logout() { // Add log out function here
this.authService.logoutPopup({
mainWindowRedirectUri: "/"
setLoginDisplay() {
this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
ngOnDestroy(): void {
this._destroying$.next(undefined);
this._destroying$.complete();
Test your code
Start the web server to listen to the port by running the following commands at a command-line prompt from the application folder:
npm install
npm start
In your browser, enter http://localhost:4200 or http://localhost:{port}, where port is the port that your web server is listening on. You should see a page that looks like the one below.
Add scopes and delegated permissions
The Microsoft Graph API requires the User.Read scope to read a user's profile. The User.Read scope is added automatically to every app registration you create in the Azure portal. Other APIs for Microsoft Graph, as well as custom APIs for your back-end server, might require additional scopes. For example, the Microsoft Graph API requires the Mail.Read scope in order to list the user's email.
As you add scopes, your users might be prompted to provide additional consent for the added scopes.
The user might be prompted for additional consents as you increase the number of scopes.
Help and support
If you need help, want to report an issue, or want to learn about your support options, see Help and support for developers.
Next steps
Delve deeper into single-page application (SPA) development on the Microsoft identity platform in our the multi-part article series.
Scenario: Single-page application