Walkthrough: Registering and configuring a SPA application with adal.js


Effective November 2020:

  • Common Data Service has been renamed to Microsoft Dataverse. Learn more
  • Some terminology in Microsoft Dataverse has been updated. For example, entity is now table and field is now column. Learn more

This article will be updated soon to reflect the latest terminology.

This walkthrough describes the process of registering and configuring the simplest Single Page Application (SPA) to access data in Microsoft Dataverse using adal.js and Cross-origin Resource Sharing (CORS). More information: Use OAuth with Cross-Origin Resource Sharing to connect a Single Page Application to Dataverse .


  • Power Apps Dataverse

  • You must have a Dataverse system user account with administrator role for Microsoft 365.

  • An Azure subscription to register your application. A trial account will also work.

  • Visual Studio 2017

Goal of this walkthrough

When you complete this walkthrough you will be able to run a simple SPA application in Visual Studio that will provide the ability for a user to authenticate and retrieve data from Dataverse. This application consists of a sample HTML page.

When you debug the application initially there will only be a Login button.

Click Login and you will be re-directed to a sign-in page to enter your credentials.

After you enter your credentials you will be directed back to the HTML page where you will find the Login button is hidden and a Logout button and a Get Accounts button are visible. You will also see a greeting using information from your user account.

Click the Get Accounts button to retrieve 10 account records from your Dataverse organization. The Get Accounts button is disabled as shown in the following screenshot:

The SimpleSPA page


The initial load of data from Dataverse may be slow as the operations to support authentication take place, but subsequent operations are much faster.

Finally, you can click on Logout button to logout.


This SPA application is not intended to represent a pattern for developing robust SPA applications. It is simplified to focus on the process of registering and configuring the application.

Create a web application project

  1. Using Visual Studio 2017, create a new ASP.NET Web Application project and use the Empty template. You can name the project whatever you like.

    You should be able to use earlier versions of Visual Studio as well, but these steps will describe using Visual Studio 2017.

  2. Add a new HTML page named SimpleSPA.html to the project and paste in the following code:

    <!DOCTYPE html>  
     <title>Simple SPA</title>  
     <meta charset="utf-8" />  
     <script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.17/js/adal.min.js"></script>  
     <script type="text/javascript">  
      "use strict";  
      //Set these variables to match your environment  
      var organizationURI = "https://[organization name].crm.dynamics.com"; //The URL of your Dataverse organization  
      var tenant = "[xxx.onmicrosoft.com]"; //The name of the Azure AD organization you use  
      var clientId = "[client id]"; //The ClientId you got when you registered the application  
      var pageUrl = "https://localhost:[PORT #]/SimpleSPA.html"; //The URL of this page in your development environment when debugging.  
      var user, authContext, message, errorMessage, loginButton, logoutButton, getAccountsButton, accountsTable, accountsTableBody;  
      //Configuration data for AuthenticationContext  
      var endpoints = {  
       orgUri: organizationURI  
      window.config = {  
       tenant: tenant,  
       clientId: clientId,  
       postLogoutRedirectUri: pageUrl,  
       endpoints: endpoints,  
       cacheLocation: 'localStorage', 
      document.onreadystatechange = function () {  
       if (document.readyState == "complete") {  
        //Set DOM elements referenced by scripts  
        message = document.getElementById("message");  
        errorMessage = document.getElementById("errorMessage");  
        loginButton = document.getElementById("login");  
        logoutButton = document.getElementById("logout");  
        getAccountsButton = document.getElementById("getAccounts");  
        accountsTable = document.getElementById("accountsTable");  
        accountsTableBody = document.getElementById("accountsTableBody");  
        //Event handlers on DOM elements  
        loginButton.addEventListener("click", login);  
        logoutButton.addEventListener("click", logout);  
        getAccountsButton.addEventListener("click", getAccounts);  
        //call authentication function  
        if (user) {  
         loginButton.style.display = "none";  
         logoutButton.style.display = "block";  
         getAccountsButton.style.display = "block";  
         var helloMessage = document.createElement("p");  
         helloMessage.textContent = "Hello " + user.profile.name;  
        else {  
         loginButton.style.display = "block";  
         logoutButton.style.display = "none";  
         getAccountsButton.style.display = "none";  
      // Function that manages authentication  
      function authenticate() {  
       //OAuth context  
       authContext = new AuthenticationContext(config);  
       // Check For & Handle Redirect From AAD After Login  
       var isCallback = authContext.isCallback(window.location.hash);  
       if (isCallback) {  
       var loginError = authContext.getLoginError();  
       if (isCallback && !loginError) {  
        window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);  
       else {  
        errorMessage.textContent = loginError;  
       user = authContext.getCachedUser();  
      //function that logs in the user  
      function login() {  
      //function that logs out the user  
      function logout() {  
       accountsTable.style.display = "none";  
       accountsTableBody.innerHTML = "";  
    //function that initiates retrieval of accounts  
      function getAccounts() {  
       getAccountsButton.disabled = true;  
       var retrievingAccountsMessage = document.createElement("p");  
       retrievingAccountsMessage.textContent = "Retrieving 10 accounts from " + organizationURI + "/api/data/v9.1/accounts";  
       // Function to perform operation is passed as a parameter to the acquireToken method  
       authContext.acquireToken(organizationURI, retrieveAccounts)  
    //Function that actually retrieves the accounts  
      function retrieveAccounts(error, token) {  
       // Handle ADAL Errors.  
       if (error || !token) {  
        errorMessage.textContent = 'ADAL error occurred: ' + error;  
       var req = new XMLHttpRequest()  
       req.open("GET", encodeURI(organizationURI + "/api/data/v9.1/accounts?$select=name,address1_city&$top=10"), true);  
       //Set Bearer token  
       req.setRequestHeader("Authorization", "Bearer " + token);  
       req.setRequestHeader("Accept", "application/json");  
       req.setRequestHeader("Content-Type", "application/json; charset=utf-8");  
       req.setRequestHeader("OData-MaxVersion", "4.0");  
       req.setRequestHeader("OData-Version", "4.0");  
       req.onreadystatechange = function () {  
        if (this.readyState == 4 /* complete */) {  
         req.onreadystatechange = null;  
         if (this.status == 200) {  
          var accounts = JSON.parse(this.response).value;  
         else {  
          var error = JSON.parse(this.response).error;  
          errorMessage.textContent = error.message;  
      //Function that writes account data to the accountsTable  
      function renderAccounts(accounts) {  
       accounts.forEach(function (account) {  
        var name = account.name;  
        var city = account.address1_city;  
        var nameCell = document.createElement("td");  
        nameCell.textContent = name;  
        var cityCell = document.createElement("td");  
        cityCell.textContent = city;  
        var row = document.createElement("tr");  
       accountsTable.style.display = "block";  
      body {  
       font-family: 'Segoe UI';  
      table {  
       border-collapse: collapse;  
      td, th {  
       border: 1px solid black;  
      #errorMessage {  
       color: red;  
      #message {  
       color: green;  
     <button id="login">Login</button>  
     <button id="logout" style="display:none;">Logout</button>  
     <button id="getAccounts" style="display:none;">Get Accounts</button>  
     <div id="errorMessage"></div>  
     <div id="message"></div>  
     <table id="accountsTable" style="display:none;">  
      <tbody id="accountsTableBody"></tbody>  
  3. Right click on the SimpleSPA.html file and select Set As Start Page to set this page as the start page for the project.

  4. In the properties of the project, select Web and under Servers note the Project URL. It should be something like https://localhost:62111/. Note the port number that is generated. You will need this in the next step.

  5. Within the SimpleSPA.html page, locate the following configuration variables and set them accordingly. You will be able to set the clientId after you complete the next part of the walkthrough.

    //Set these variables to match your environment  
    var organizationURI = "https://[organization name].crm.dynamics.com"; //The URL to connect to Power Apps Dataverse  
    var tenant = "[xxx.onmicrosoft.com]"; //The name of the Azure AD organization you use  
    var clientId = "[client id]"; //The ClientId you got when you registered the application  
    var pageUrl = "https://localhost:[PORT #]/SimpleSPA.html"; //The URL of this page in your development environment when debugging.  

Register the application

  1. Sign in to the Azure portal using an account with administrator permission. You must use an account in the same Microsoft 365 subscription (tenant) as you intend to register the app with. You can also access the Azure portal through the Microsoft 365 admin center by expanding the ADMIN item in the left navigation pane and selecting Azure AD.


    If you don't have an Azure tenant (account) or you do have one but your Microsoft 365 subscription with Dataverse is not available in your Azure subscription, following the instructions in the topic Set up Azure Active Directory access for your Developer Site to associate the two accounts.

    If you don't have an account, you can sign up for one by using a credit card. However, the account is free for application registration and your credit card won't be charged if you only follow the procedures called out in this topic to register one or more apps. More information: Active Directory Pricing Details.

  2. Click on Azure Active Directory in the left column of the page. You may need to scroll the left column to see the Azure Active Directory icon and label.

  3. Now select Enterprise Applications in the panel that opens up.

    Select Enterprise Applications

  4. Select New application(near the top of the page), and then under Add your own app select Application you're developing.

    Select Application you're developing

  5. Now click on Ok, take me to App Registrations to register my new application.

    Select Ok, take me to App Registrations

  6. Now click on New application registration(near the top of the page).

    Select New application registration

  7. Enter the following information :

    • Name
      The name of the application.

    • Supported account types
      Select Accounts in any organizational directory.

    • Redirect URL
      This is the URL which the user should be redirected to after they sign in. Select Web from the drop down list. For debugging purposes in Visual Studio it should be https://localhost:####/SimpleSPA.html where #### represents the port number you got from step 4 of the Create a web application project procedure. Then click on Register at the end of the page.

    Enter details

  8. In the tab of the newly registered app, copy the Application (client) ID. Set the clientId variable in the SimpleSPA.html page to this value. Refer to step 5 of the Create a web application project procedure.

  9. Now click on API permissions and then select Add a permission.

    Select Required permissions

  10. Select Dynamics CRM under Microsoft APIs tab.

    Select Dynamics CRM Online under Select an API

  11. Click on Delegated permissions tab, select all permissions and click on Add permissions at the end of the page.

    Select all Delegated permissions

  12. Then select Done. You will see a row for Dynamics CRM added.

  13. Now close the API permissions tab. In the registered app tab, select Manifest.

  14. Locate the line: "oauth2AllowImplicitFlow": false, and change false to true and then click on Save to save the file.

    Set oauth2AllowImplicitFlow to true in Manifest file

  15. For successful execution of your application, you will also need to grant administrator consent to it. To do this, login as a tenant admin in your Azure management portal and select Azure Active Directory. Then click on Enterprise Applications and from the list of applications that appear, select the application that you just created.

    Grant administrator consent to your application

  16. Now select API permissions as shown above, and click on Grant admin consent for<your AAD Org name>.

    Click on Grant admin consent button

  17. Once you click on this button, it will open a login window and ask you whether you wish to grant the requested permissions to your application. Click on Accept to proceed.

    Click on Accept to grant the requested permissions

  18. Once this is done, proceed to debugging the application.


You need to enable the ID tokens option in the Authentication tab for the app you have registered.

Debugging the application

  1. Set the browser to use Microsoft Edge or Google Chrome.


    Internet Explorer will not work for debugging in this situation.

  2. Press F5 to start debugging. You should expect the behavior described in Goal of this walkthrough.

If you don't get the results you expect, double-check the values you set while registering the application and configuring the SimpleSPA.html code.

See also

Create client applications
Tutorial: Register an app with Azure Active Directory
Build web applications using Server to Server(S2S) authentication
Use OAuth with Cross-Origin Resource Sharing to connect a Single Page Application to Dataverse