Call the Microsoft Graph API from a JavaScript single-page application (SPA)

This guide demonstrates how a JavaScript single-page application (SPA) can sign in personal, work and school accounts, get an access token, and call the Microsoft Graph API or other APIs that require access tokens from the Azure Active Directory v2.0 endpoint.

How the sample app generated by this guide works

How the sample app generated by this guide works

More Information

The sample application created by this guide enables a JavaScript SPA to query the Microsoft Graph API or a Web API that accepts tokens from Azure Active Directory v2.0 endpoint. For 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 the Microsoft Authentication Library (MSAL).

Libraries

This guide uses the following library:

Library Description
msal.js Microsoft Authentication Library for JavaScript Preview

Note

msal.js targets the Azure Active Directory v2.0 endpoint - which enables personal, school and work accounts to sign in and acquire tokens. The Azure Active Directory v2.0 endpoint has some limitations. To understand differences between the v1.0 and v2.0 endpoints read the Endpoint comparison guide.

Setting up your web server or project

Prefer to download this sample's project instead?

or

And then skip to the Configuration step to configure the code sample before executing it.

Prerequisites

A local web server such as Node.js, .NET Core, or IIS Express integration with Visual Studio 2017 is required to run this tutorial.

Instructions in this guide are based on both Node.js and Visual Studio 2017, but feel free to use any other development environment or Web Server.

Create your project

Option 1: Node/ other web servers

Make sure you have installed Node.js, then follow the step below:

  • Create a folder to host your application.

Option 2: Visual Studio

If you are using Visual Studio and are creating a new project, follow the steps below to create a new Visual Studio solution:

  1. In Visual Studio: File > New > Project
  2. Under Visual C#\Web, select ASP.NET Web Application (.NET Framework)
  3. Enter a name for your application and select OK
  4. Under New ASP.NET Web Application, select Empty

Create your single page application’s UI

  1. Create an index.html file for your JavaScript SPA. If you are using Visual Studio, select the project (project root folder), right click and select: Add > New Item > HTML page and name it index.html.

  2. Add the following code to your page:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Quickstart for MSAL JS</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.3.4/bluebird.min.js"></script>
        <script src="https://secure.aadcdn.microsoftonline-p.com/lib/0.2.3/js/msal.js"></script>
        <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    </head>
    <body>
        <h2>Welcome to MSAL.js Quickstart</h2><br/>
        <h4 id="WelcomeMessage"></h4>
        <button id="SignIn" onclick="signIn()">Sign In</button><br/><br/>
        <pre id="json"></pre>
        <script>
            //JS code
        </script>
    </body>
    </html>
    

Use the Microsoft Authentication Library (MSAL) to sign in the user

  1. Add the following code to your index.html file within the <script></script> tags:
//Pass null for default authority (https://login.microsoftonline.com/common)
var myMSALObj = new Msal.UserAgentApplication(applicationConfig.clientID, null, acquireTokenRedirectCallBack,
    {storeAuthStateInCookie: true, cacheLocation: "localStorage"});

function signIn() {
    myMSALObj.loginPopup(applicationConfig.graphScopes).then(function (idToken) {
        //Login Success
        showWelcomeMessage();
        acquireTokenPopupAndCallMSGraph();
    }, function (error) {
        console.log(error);
    });
}

function acquireTokenPopupAndCallMSGraph() {
    //Call acquireTokenSilent (iframe) to obtain a token for Microsoft Graph
    myMSALObj.acquireTokenSilent(applicationConfig.graphScopes).then(function (accessToken) {
        callMSGraph(applicationConfig.graphEndpoint, accessToken, graphAPICallback);
    }, function (error) {
        console.log(error);
        // Call acquireTokenPopup (popup window) in case of acquireTokenSilent failure due to consent or interaction required ONLY
        if (error.indexOf("consent_required") !== -1 || error.indexOf("interaction_required") !== -1 || error.indexOf("login_required") !== -1) {
            myMSALObj.acquireTokenPopup(applicationConfig.graphScopes).then(function (accessToken) {
                callMSGraph(applicationConfig.graphEndpoint, accessToken, graphAPICallback);
            }, function (error) {
                console.log(error);
            });
        }
    });
}

function graphAPICallback(data) {
    //Display user data on DOM
    var divWelcome = document.getElementById('WelcomeMessage');
    divWelcome.innerHTML += " to Microsoft Graph API!!";
    document.getElementById("json").innerHTML = JSON.stringify(data, null, 2);
}

function showWelcomeMessage() {
    var divWelcome = document.getElementById('WelcomeMessage');
    divWelcome.innerHTML += 'Welcome ' + myMSALObj.getUser().name;
    var loginbutton = document.getElementById('SignIn');
    loginbutton.innerHTML = 'Sign Out';
    loginbutton.setAttribute('onclick', 'signOut();');
}

// This function can be removed if you do not need to support IE
function acquireTokenRedirectAndCallMSGraph() {
    //Call acquireTokenSilent (iframe) to obtain a token for Microsoft Graph
    myMSALObj.acquireTokenSilent(applicationConfig.graphScopes).then(function (accessToken) {
      callMSGraph(applicationConfig.graphEndpoint, accessToken, graphAPICallback);
    }, function (error) {
        console.log(error);
        //Call acquireTokenRedirect in case of acquireToken Failure
        if (error.indexOf("consent_required") !== -1 || error.indexOf("interaction_required") !== -1 || error.indexOf("login_required") !== -1) {
            myMSALObj.acquireTokenRedirect(applicationConfig.graphScopes);
        }
    });
}

function acquireTokenRedirectCallBack(errorDesc, token, error, tokenType)
{
 if(tokenType === "access_token")
 {
     callMSGraph(applicationConfig.graphEndpoint, token, graphAPICallback);
 } else {
     console.log("token type is:"+tokenType);
 }
}


// Browser check variables
var ua = window.navigator.userAgent;
var msie = ua.indexOf('MSIE ');
var msie11 = ua.indexOf('Trident/');
var msedge = ua.indexOf('Edge/');
var isIE = msie > 0 || msie11 > 0;
var isEdge = msedge > 0;

//If you support IE, our recommendation is that you sign-in using Redirect APIs
//If you as a developer are testing using Edge InPrivate mode, please add "isEdge" to the if check
if (!isIE) {
    if (myMSALObj.getUser()) {// avoid duplicate code execution on page load in case of iframe and popup window.
        showWelcomeMessage();
        acquireTokenPopupAndCallMSGraph();
    }
}
else {
    document.getElementById("SignIn").onclick = function () {
        myMSALObj.loginRedirect(applicationConfig.graphScopes);
    };
    if (myMSALObj.getUser() && !myMSALObj.isCallback(window.location.hash)) {// avoid duplicate code execution on page load in case of iframe and popup window.
        showWelcomeMessage();
        acquireTokenRedirectAndCallMSGraph();
    }
}

More Information

After a user clicks the Sign In button for the first time, the signIn method calls loginPopup to sign in the user. This method results in opening a popup window with the Microsoft Azure Active Directory v2.0 endpoint to prompt and validate the user's credentials. As a result of a successful sign-in, the user is redirected back to the original index.html page, and a token is received, processed by msal.js and the information contained in the token is cached. This token is known as the ID token and contains basic information about the user, such as the user display name. If you plan to use any data provided by this token for any purposes, you need to make sure this token is validated by your backend server to guarantee that the token was issued to a valid user for your application.

The SPA generated by this guide calls acquireTokenSilent and/or acquireTokenPopup to acquire an access token used to query the Microsoft Graph API for user profile info. If you need a sample that validates the ID token, take a look at this sample application in GitHub – the sample uses an ASP.NET Web API for token validation.

Getting a user token interactively

After the initial sign-in, you do not want to ask users to reauthenticate every time they need to request a token to access a resource – so acquireTokenSilent should be used most of the time to acquire tokens. There are situations however that you need to force users to interact with Azure Active Directory v2.0 endpoint – some examples include:

  • Users may need to reenter their credentials because the password has expired
  • Your application is requesting access to a resource that the user needs to consent to
  • Two factor authentication is required

Calling the acquireTokenPopup(scope) results in a popup window (or acquireTokenRedirect(scope) results in redirecting users to the Azure Active Directory v2.0 endpoint) where users need to interact by either confirming their credentials, giving the consent to the required resource, or completing the two factor authentication.

Getting a user token silently

The acquireTokenSilent method handles token acquisitions and renewal without any user interaction. After loginPopup (or loginRedirect) is executed for the first time, acquireTokenSilent is the method commonly used to obtain tokens used to access protected resources for subsequent calls - as calls to request or renew tokens are made silently. acquireTokenSilent may fail in some cases – for example, the user's password has expired. Your application can handle this exception in two ways:

  1. Make a call to acquireTokenPopup immediately, which results in prompting the user to sign in. This pattern is commonly used in online applications where there is no unauthenticated content in the application available to the user. The sample generated by this guided setup uses this pattern.

  2. Applications can also make a visual indication to the user that an interactive sign-in is required, so the user can select the right time to sign in, or the application can retry acquireTokenSilent at a later time. This is commonly used when the user can use other functionality of the application without being disrupted - for example, there is unauthenticated content available in the application. In this case, the user can decide when they want to sign in to access the protected resource, or to refresh the outdated information.

Note

The above code uses the loginRedirect and acquireTokenRedirect methods when the browser used is Internet Explorer due to a known issue related to handling of popup windows by Internet Explorer browser.

Call the Microsoft Graph API using the token you just obtained

Add the following code to your index.html file within the <script></script> tags:

function callMSGraph(theUrl, accessToken, callback) {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200)
            callback(JSON.parse(this.responseText));
    }
    xmlHttp.open("GET", theUrl, true); // true for asynchronous
    xmlHttp.setRequestHeader('Authorization', 'Bearer ' + accessToken);
    xmlHttp.send();
}

More information on making a REST call against a protected API

In the sample application created by this guide, the callMSGraph() method is used to make an HTTP GET request against a protected resource that requires a token and then return the content to the caller. This method adds the acquired token in the HTTP Authorization header. For the sample application created by this guide, the resource is the Microsoft Graph API me endpoint – which displays the user's profile information.

Add a method to sign out the user

Add the following code to your index.html file within the <script></script> tags:

/**
 * Sign out the user
 */
 function signOut() {
     myMSALObj.logout();
 }

Register your application

There are multiple ways to register an application. Select the option that best fits your needs:

Option 1: Register your application (Express mode)

  1. Sign in to the Azure portal app registration (preview) to register an application.
  2. On the Register an application page, enter a name for your application.
  3. Under Supported account types, select Accounts in any organizational directory and personal Microsoft accounts.
  4. When finished, select Register.
  5. Follow the quickstart instructions to download and automatically configure your new application for you in one click.

Option 2: Register your application (Advanced mode)

  1. Sign in to the Azure portal to register an application.
  2. If your account gives you access to more than one tenant, select your account in the top right corner, and set your portal session to the desired Azure AD tenant.
  3. In the left-hand navigation pane, select the Azure Active Directory service, and then select App registrations (Preview) > New registration.
  4. When the Register an application page appears, enter a name for your application.
  5. Under Supported account types, select Accounts in any organizational directory and personal Microsoft accounts.
  6. Under the Redirect URI section, select the Web platform and set the value to the application's URL based on your web server. See the sections below for instructions on how to set and obtain the redirect URL in Visual Studio and Node.
  7. When finished, select Register.
  8. On the app Overview page, note down the Application (client) ID value.
  9. This quickstart requires the Implicit grant flow to be enabled. In the left-hand navigation pane of the registered application, select Authentication.
  10. In Advanced settings, under Implicit grant, enable both ID tokens and Access tokens checkboxes. ID tokens and access tokens are required since this app needs to sign in users and call an API.
  11. Select Save.

Setting the redirect URL for Node

For Node.js, you can set the web server port in the server.js file. This tutorial uses the port 30662 for reference but you can use any other available port. Follow the instructions below to set up a redirect URL in the application registration information:

  • Switch back to the Application Registration and set http://localhost:30662/ as a Redirect URL, or use http://localhost:[port]/ if you are using a custom TCP port (where [port] is the custom TCP port number).

Visual Studio instructions for obtaining the redirect URL

Follow these steps to obtain the redirect URL:

  1. In Solution Explorer, select the project and look at the Properties window. If you don’t see a Properties window, press F4.
  2. Copy the value from URL to the clipboard:
    Project properties
  3. Switch back to the Application Registration and set the value as a Redirect URL.

Configure your JavaScript SPA

  1. In the index.html file created during project setup, add the application registration information. Add the following code at the top within the <script></script> tags in the body of your index.html file:

    var applicationConfig = {
        clientID: "Enter_the_Application_Id_here",
        authority: "https://login.microsoftonline.com/common",
        graphScopes: ["user.read"],
        graphEndpoint: "https://graph.microsoft.com/v1.0/me"
    };
    
  1. Replace Enter the application Id here with the application ID you just registered.

Test your code

Test with Node

If you're not using Visual Studio, make sure your web server is started.

  1. Configure the server to listen to a TCP port that's based on the location of your index.html file. For Node, start the web server to listen to the port by running the following commands on a command line prompt from the application folder:

    npm install
    node server.js
    
  2. Open the browser and type http://localhost:30662 or http://localhost:{port} where port is the port that your web server is listening to. You should see the contents of your index.html file and the Sign In button.

Test with Visual Studio

If you're using Visual Studio, make sure to select the project solution and press F5 to run your project. The browser opens to the http://localhost:{port} location and you see the Sign In button.

Test your application

After the browser loads your index.html file, click Sign In. You will be prompted to sign in with the Microsoft Azure Active Directory (Azure AD) v2.0 endpoint:

Sign in to your JavaScript SPA account

The first time that you sign in to your application, you're prompted to provide your consent to allow the application to access your profile and to sign you in:

Provide your consent for application access

View application results

After you sign in, you should see your user profile information returned in the Microsoft Graph API response displayed on the page.

Expected results from Microsoft Graph API call

More information about scopes and delegated permissions

The Microsoft Graph API requires the user.read scope to read a user's profile. This scope is automatically added by default in every application that's registered on the registration 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 Calendars.Read scope to list the user’s calendars.

To access the user’s calendars in the context of an application, add the Calendars.Read delegated permission to the application registration information. Then, add the Calendars.Read scope to the acquireTokenSilent call.

Note

The user might be prompted for additional consents as you increase the number of scopes.

If a back-end API doesn't require a scope (not recommended), you can use the clientId as the scope in the calls to acquire tokens.

Help and support

If you need help, want to report an issue, or want to learn more about your support options, see the following article: