Tutorial: Conectar usuários e chamar a API do Microsoft Graph de um SPA (aplicativo de página única) JavaScript usando o fluxo de código de autenticação

Neste tutorial, você criará um SPA (aplicativo de página única) JavaScript que conecta usuários e chama o Microsoft Graph usando o fluxo de código de autorização com PKCE. O SPA que você cria usa a MSAL (Biblioteca de Autenticação da Microsoft) para JavaScript v2.0.

Neste tutorial:

  • Executar o fluxo do código de autorização do OAuth 2.0 com PKCE
  • Entrar em contas Microsoft pessoais, bem como contas corporativas e de estudante
  • Adquirir um token de acesso
  • Chame a API do Microsoft Graph ou a sua API que exige tokens de acesso obtidos da plataforma de identidade da Microsoft

A MSAL.js 2.0 tem aprimoramentos com relação à MSAL.js 1.0, dando suporte ao fluxo do código de autorização no navegador em vez do fluxo de concessão implícita. A MSAL.js 2.0 NÃO dá suporte ao fluxo implícito.

Pré-requisitos

Como o aplicativo tutorial funciona

Diagram showing the authorization code flow in a single-page application

O aplicativo criado neste tutorial permite que um SPA JavaScript consulte a API do Microsoft Graph adquirindo tokens de segurança da plataforma de identidade da Microsoft. Nesse cenário, depois que um usuário se conecta, um token de acesso é adicionado às solicitações HTTP no cabeçalho de autorização. A aquisição e a renovação de tokens são manipuladas pela Biblioteca de Autenticação da Microsoft (MSAL.js) para JavaScript.

Este tutorial usa MSAL.js a Biblioteca de Autenticação da Microsoft para o pacote de navegador do JavaScript v2.0.

Obter o exemplo de código concluído

Mas você pode baixar o projeto de exemplo concluído deste tutorial clonando o repositório ms-identity-javascript-v2.

git clone https://github.com/Azure-Samples/ms-identity-javascript-v2.git

Para executar o projeto baixado em seu ambiente de desenvolvimento local, comece criando um servidor localhost para o aplicativo, conforme descrito na etapa 1 de criar seu projeto. Depois de terminar, você pode configurar o exemplo de código indo diretamente para a etapa de configuração.

Para continuar com o tutorial e criar o aplicativo por conta própria, vá para a próxima seção, Criar seu projeto.

Criar seu projeto

Após instalar o Node.js, crie uma pasta para hospedar seu aplicativo, como msal-spa-tutorial.

Em seguida, implemente um servidor Web pequeno do Express para atender ao seu arquivo index.html.

  1. Primeiro, altere o diretório do projeto em seu terminal e execute os comandos seguintes comandos npm:

    npm init -y
    npm install @azure/msal-browser
    npm install express
    npm install morgan
    npm install yargs
    
  2. Em seguida, crie um arquivo chamado server.js e adicione o seguinte código:

    const express = require('express');
    const morgan = require('morgan');
    const path = require('path');
    
    const DEFAULT_PORT = process.env.PORT || 3000;
    
    // initialize express.
    const app = express();
    
    // Initialize variables.
    let port = DEFAULT_PORT;
    
    // Configure morgan module to log all requests.
    app.use(morgan('dev'));
    
    // Setup app folders.
    app.use(express.static('app'));
    
    // Set up a route for index.html
    app.get('*', (req, res) => {
        res.sendFile(path.join(__dirname + '/index.html'));
    });
    
    // Start the server.
    app.listen(port);
    console.log(`Listening on port ${port}...`);
    

Criar a interface do usuário do SPA

  1. Crie uma pasta app no diretório do projeto e, nela, crie um arquivo index.html para seu SPA JavaScript. Esse arquivo implementa uma interface do usuário criada com o Bootstrap 4 Framework e importa arquivos de script para configuração, autenticação e chamadas à API.

    No arquivo index.html, adicione o seguinte código:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
      <title>Microsoft identity platform</title>
      <link rel="SHORTCUT ICON" href="./favicon.svg" type="image/x-icon">
    
       <!-- msal.min.js can be used in the place of msal.js; included msal.js to make debug easy -->
      <script src="https://alcdn.msauth.net/browser/2.30.0/js/msal-browser.js"
        integrity="sha384-o4ufwq3oKqc7IoCcR08YtZXmgOljhTggRwxP2CLbSqeXGtitAxwYaUln/05nJjit"
        crossorigin="anonymous"></script>
      
      <!-- adding Bootstrap 4 for UI components  -->
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
      <link rel="SHORTCUT ICON" href="https://c.s-microsoft.com/favicon.ico?v2" type="image/x-icon">
    </head>
    
    <body>
      <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
        <a class="navbar-brand" href="/">Microsoft identity platform</a>
        <div class="btn-group ml-auto dropleft">
          <button type="button" id="SignIn" class="btn btn-secondary" onclick="signIn()">
            Sign In
          </button>
        </div>
      </nav>
      <br>
      <h5 class="card-header text-center">Vanilla JavaScript SPA calling MS Graph API with MSAL.js</h5>
      <br>
      <div class="row" style="margin:auto">
        <div id="card-div" class="col-md-3" style="display:none">
          <div class="card text-center">
            <div class="card-body">
              <h5 class="card-title" id="WelcomeMessage">Please sign-in to see your profile and read your mails</h5>
              <div id="profile-div"></div>
              <br>
              <br>
              <button class="btn btn-primary" id="seeProfile" onclick="seeProfile()">See Profile</button>
              <br>
              <br>
              <button class="btn btn-primary" id="readMail" onclick="readMail()">Read Mails</button>
            </div>
          </div>
        </div>
        <br>
        <br>
        <div class="col-md-4">
          <div class="list-group" id="list-tab" role="tablist">
          </div>
        </div>
        <div class="col-md-5">
          <div class="tab-content" id="nav-tabContent">
          </div>
        </div>
      </div>
      <br>
      <br>
    
      <!-- importing bootstrap.js and supporting js libraries -->
      <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
        integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
        crossorigin="anonymous"></script>
      <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
        integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
        crossorigin="anonymous"></script>
      <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
        integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
        crossorigin="anonymous"></script>
    
      <!-- importing app scripts (load order is important) -->
      <script type="text/javascript" src="./authConfig.js"></script>
      <script type="text/javascript" src="./graphConfig.js"></script>
      <script type="text/javascript" src="./ui.js"></script>
    
      <!-- <script type="text/javascript" src="./authRedirect.js"></script>   -->
      <!-- uncomment the above line and comment the line below if you would like to use the redirect flow -->
      <script type="text/javascript" src="./authPopup.js"></script>
      <script type="text/javascript" src="./graph.js"></script>
    </body>
    
    </html>
    
  2. Em seguida, também na pasta app, crie um arquivo chamado ui.js e adicione o código a seguir. Este arquivo vai acessar e atualizar elementos DOM.

    // Select DOM elements to work with
    const welcomeDiv = document.getElementById("WelcomeMessage");
    const signInButton = document.getElementById("SignIn");
    const cardDiv = document.getElementById("card-div");
    const mailButton = document.getElementById("readMail");
    const profileButton = document.getElementById("seeProfile");
    const profileDiv = document.getElementById("profile-div");
    
    function showWelcomeMessage(username) {
        // Reconfiguring DOM elements
        cardDiv.style.display = 'initial';
        welcomeDiv.innerHTML = `Welcome ${username}`;
        signInButton.setAttribute("onclick", "signOut();");
        signInButton.setAttribute('class', "btn btn-success")
        signInButton.innerHTML = "Sign Out";
    }
    
    function updateUI(data, endpoint) {
        console.log('Graph API responded at: ' + new Date().toString());
    
        if (endpoint === graphConfig.graphMeEndpoint) {
            profileDiv.innerHTML = ''
            const title = document.createElement('p');
            title.innerHTML = "<strong>Title: </strong>" + data.jobTitle;
            const email = document.createElement('p');
            email.innerHTML = "<strong>Mail: </strong>" + data.mail;
            const phone = document.createElement('p');
            phone.innerHTML = "<strong>Phone: </strong>" + data.businessPhones[0];
            const address = document.createElement('p');
            address.innerHTML = "<strong>Location: </strong>" + data.officeLocation;
            profileDiv.appendChild(title);
            profileDiv.appendChild(email);
            profileDiv.appendChild(phone);
            profileDiv.appendChild(address);
    
        } else if (endpoint === graphConfig.graphMailEndpoint) {
            if (!data.value) {
                alert("You do not have a mailbox!")
            } else if (data.value.length < 1) {
                alert("Your mailbox is empty!")
            } else {
                const tabContent = document.getElementById("nav-tabContent");
                const tabList = document.getElementById("list-tab");
                tabList.innerHTML = ''; // clear tabList at each readMail call
    
                data.value.map((d, i) => {
                    // Keeping it simple
                    if (i < 10) {
                        const listItem = document.createElement("a");
                        listItem.setAttribute("class", "list-group-item list-group-item-action")
                        listItem.setAttribute("id", "list" + i + "list")
                        listItem.setAttribute("data-toggle", "list")
                        listItem.setAttribute("href", "#list" + i)
                        listItem.setAttribute("role", "tab")
                        listItem.setAttribute("aria-controls", i)
                        listItem.innerHTML = d.subject;
                        tabList.appendChild(listItem)
    
                        const contentItem = document.createElement("div");
                        contentItem.setAttribute("class", "tab-pane fade")
                        contentItem.setAttribute("id", "list" + i)
                        contentItem.setAttribute("role", "tabpanel")
                        contentItem.setAttribute("aria-labelledby", "list" + i + "list")
                        contentItem.innerHTML = "<strong> from: " + d.from.emailAddress.address + "</strong><br><br>" + d.bodyPreview + "...";
                        tabContent.appendChild(contentItem);
                    }
                });
            }
        }
    }
    

Registre seu aplicativo

Siga as etapas em Aplicativo de página única: registro de aplicativo para criar um registro de aplicativo para o SPA.

Na etapa URI de redirecionamento: MSAL.js 2.0 com fluxo do código de autenticação, insira http://localhost:3000, o local padrão onde o aplicativo deste tutorial é executado.

Se quiser usar uma porta diferente, insira http://localhost:<port>, em que <port> é o número da porta TCP preferencial. Se você especificar um número da porta diferente de 3000, atualize também server.js com seu número de porta preferencial.

Configurar o JavaScript SPA

Crie um arquivo chamado authConfig.js na pasta app que conterá os parâmetros de configuração para autenticação, depois adicione a ele o seguinte código:

/**
 * Configuration object to be passed to MSAL instance on creation. 
 * For a full list of MSAL.js configuration parameters, visit:
 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md 
 */
const msalConfig = {
    auth: {
        // 'Application (client) ID' of app registration in Azure portal - this value is a GUID
        clientId: "Enter_the_Application_Id_Here",
        // Full directory URL, in the form of https://login.microsoftonline.com/<tenant-id>
        authority: "Enter_the_Cloud_Instance_Id_HereEnter_the_Tenant_Info_Here",
        // Full redirect URL, in form of http://localhost:3000
        redirectUri: "Enter_the_Redirect_Uri_Here",
    },
    cache: {
        cacheLocation: "sessionStorage", // This configures where your cache will be stored
        storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
    },
    system: {	
        loggerOptions: {	
            loggerCallback: (level, message, containsPii) => {	
                if (containsPii) {		
                    return;		
                }		
                switch (level) {		
                    case msal.LogLevel.Error:		
                        console.error(message);		
                        return;		
                    case msal.LogLevel.Info:		
                        console.info(message);		
                        return;		
                    case msal.LogLevel.Verbose:		
                        console.debug(message);		
                        return;		
                    case msal.LogLevel.Warning:		
                        console.warn(message);		
                        return;		
                }	
            }	
        }	
    }
};

/**
 * Scopes you add here will be prompted for user consent during sign-in.
 * By default, MSAL.js will add OIDC scopes (openid, profile, email) to any login request.
 * For more information about OIDC scopes, visit: 
 * https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes
 */
const loginRequest = {
    scopes: ["User.Read"]
};

/**
 * Add here the scopes to request when obtaining an access token for MS Graph API. For more information, see:
 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/resources-and-scopes.md
 */
const tokenRequest = {
    scopes: ["User.Read", "Mail.Read"],
    forceRefresh: false // Set this to "true" to skip a cached token and go to the server to get a new token
};

Ainda na pasta app, crie um arquivo chamado graphConfig.js. Adicione o seguinte código para fornecer ao aplicativo os parâmetros de configuração para chamar a API do Microsoft Graph:

// Add here the endpoints for MS Graph API services you would like to use.
const graphConfig = {
    graphMeEndpoint: "Enter_the_Graph_Endpoint_Herev1.0/me",
    graphMailEndpoint: "Enter_the_Graph_Endpoint_Herev1.0/me/messages"
};

Modifique os valores na seção graphConfig conforme descrito aqui:

  • Enter_the_Graph_Endpoint_Here é a instância da API do Microsoft Graph com a qual o aplicativo deve se comunicar.
    • Para o ponto de extremidade global da API do Microsoft Graph, substitua as duas instâncias dessa cadeia de caracteres por https://graph.microsoft.com.
    • Para pontos de extremidade em implantações de nuvens nacionais, confira Implantações de nuvens nacionais na documentação do Microsoft Graph.

Os valores de graphMeEndpoint e graphMailEndpoint em seu graphConfig.js deverão ser semelhantes ao seguinte se você estiver usando o ponto de extremidade global:

graphMeEndpoint: "https://graph.microsoft.com/v1.0/me",
graphMailEndpoint: "https://graph.microsoft.com/v1.0/me/messages"

Use a MSAL (Biblioteca de Autenticação da Microsoft) para conectar o usuário

Pop-up

Na pasta app, crie um arquivo chamado authPopup.js e adicione o seguinte código de autenticação e aquisição de token para o pop-up de logon:

// Create the main myMSALObj instance
// configuration parameters are located at authConfig.js
const myMSALObj = new msal.PublicClientApplication(msalConfig);

let username = "";

function selectAccount() {

    /**
     * See here for more info on account retrieval: 
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
     */

    const currentAccounts = myMSALObj.getAllAccounts();
    if (currentAccounts.length === 0) {
        return;
    } else if (currentAccounts.length > 1) {
        // Add choose account code here
        console.warn("Multiple accounts detected.");
    } else if (currentAccounts.length === 1) {
        username = currentAccounts[0].username;
        showWelcomeMessage(username);
    }
}

function handleResponse(response) {

    /**
     * To see the full list of response object properties, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#response
     */

    if (response !== null) {
        username = response.account.username;
        showWelcomeMessage(username);
    } else {
        selectAccount();
    }
}

function signIn() {

    /**
     * You can pass a custom request object below. This will override the initial configuration. For more information, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request
     */

    myMSALObj.loginPopup(loginRequest)
        .then(handleResponse)
        .catch(error => {
            console.error(error);
        });
}

function signOut() {

    /**
     * You can pass a custom request object below. This will override the initial configuration. For more information, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request
     */

    const logoutRequest = {
        account: myMSALObj.getAccountByUsername(username),
        postLogoutRedirectUri: msalConfig.auth.redirectUri,
        mainWindowRedirectUri: msalConfig.auth.redirectUri
    };

    myMSALObj.logoutPopup(logoutRequest);
}

function getTokenPopup(request) {

    /**
     * See here for more info on account retrieval: 
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
     */
    request.account = myMSALObj.getAccountByUsername(username);
    
    return myMSALObj.acquireTokenSilent(request)
        .catch(error => {
            console.warn("silent token acquisition fails. acquiring token using popup");
            if (error instanceof msal.InteractionRequiredAuthError) {
                // fallback to interaction when silent call fails
                return myMSALObj.acquireTokenPopup(request)
                    .then(tokenResponse => {
                        console.log(tokenResponse);
                        return tokenResponse;
                    }).catch(error => {
                        console.error(error);
                    });
            } else {
                console.warn(error);   
            }
    });
}

function seeProfile() {
    getTokenPopup(loginRequest)
        .then(response => {
            callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI);
        }).catch(error => {
            console.error(error);
        });
}

function readMail() {
    getTokenPopup(tokenRequest)
        .then(response => {
            callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI);
        }).catch(error => {
            console.error(error);
        });
}

selectAccount();

Redirecionar

Crie um arquivo chamado authRedirect.js na pasta app e adicione o seguinte código de autenticação e aquisição de token para o redirecionamento de logon:

// Create the main myMSALObj instance
// configuration parameters are located at authConfig.js
const myMSALObj = new msal.PublicClientApplication(msalConfig);

let username = "";

/**
 * A promise handler needs to be registered for handling the
 * response returned from redirect flow. For more information, visit:
 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/acquire-token.md
 */
myMSALObj.handleRedirectPromise()
    .then(handleResponse)
    .catch((error) => {
        console.error(error);
    });

function selectAccount () {

    /**
     * See here for more info on account retrieval: 
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
     */

    const currentAccounts = myMSALObj.getAllAccounts();

    if (currentAccounts.length === 0) {
        return;
    } else if (currentAccounts.length > 1) {
        // Add your account choosing logic here
        console.warn("Multiple accounts detected.");
    } else if (currentAccounts.length === 1) {
        username = currentAccounts[0].username;
        showWelcomeMessage(username);
    }
}

function handleResponse(response) {
    if (response !== null) {
        username = response.account.username;
        showWelcomeMessage(username);
    } else {
        selectAccount();
    }
}

function signIn() {

    /**
     * You can pass a custom request object below. This will override the initial configuration. For more information, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request
     */

    myMSALObj.loginRedirect(loginRequest);
}

function signOut() {

    /**
     * You can pass a custom request object below. This will override the initial configuration. For more information, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request
     */

    const logoutRequest = {
        account: myMSALObj.getAccountByUsername(username),
        postLogoutRedirectUri: msalConfig.auth.redirectUri,
    };

    myMSALObj.logoutRedirect(logoutRequest);
}

function getTokenRedirect(request) {
    /**
     * See here for more info on account retrieval: 
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
     */
    request.account = myMSALObj.getAccountByUsername(username);

    return myMSALObj.acquireTokenSilent(request)
        .catch(error => {
            console.warn("silent token acquisition fails. acquiring token using redirect");
            if (error instanceof msal.InteractionRequiredAuthError) {
                // fallback to interaction when silent call fails
                return myMSALObj.acquireTokenRedirect(request);
            } else {
                console.warn(error);   
            }
        });
}

function seeProfile() {
    getTokenRedirect(loginRequest)
        .then(response => {
            callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI);
        }).catch(error => {
            console.error(error);
        });
}

function readMail() {
    getTokenRedirect(tokenRequest)
        .then(response => {
            callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI);
        }).catch(error => {
            console.error(error);
        });
}

Como o código funciona

Quando um usuário selecione o botão Entrar pela primeira vez, o método signIn chama loginPopup para conectar o usuário. O método loginPopup abre uma janela pop-up com o ponto de extremidade da plataforma de identidade da Microsoft para solicitar e validar as credenciais do usuário. Após uma entrada bem-sucedida, msal.js inicia o fluxo de código de autorização.

Neste ponto, um código de autorização protegido por PKCE é enviado para o ponto de extremidade de token protegido por CORS e é trocado por tokens. Um token de ID, um token de acesso e um token de atualização são recebidos pelo seu aplicativo e processados por msal.js e as informações contidas no token são armazenadas em cache.

O token de ID contém informações básicas sobre o usuário, como o nome de exibição dele. Se você planeja usar dados fornecidos pelo token de ID, seu servidor de back-end precisa validá-los para ter certeza de que o token foi emitido para um usuário válido para o seu aplicativo.

O token de acesso tem um tempo de vida limitado e expira após 24 horas. O token de atualização pode ser usado para obter silenciosamente novos tokens de acesso.

O SPA criado neste tutorial chama acquireTokenSilent e/ou acquireTokenPopup para adquirir um token de acesso usado para consultar a API do Microsoft Graph para obter informações de perfil do usuário. Se você precisar de uma amostra que valida o token de ID, confira o aplicativo de exemplo active-directory-javascript-singlepageapp-dotnet-webapi-v2 no GitHub. Esta amostra usa um ASP.NET Web API para validação de token.

Obter um token de usuário interativamente

Depois da entrada inicial, o aplicativo não deve solicitar que os usuários autentiquem novamente sempre que precisam acessar um recurso protegido (ou seja, solicitar um token). Para evitar essas solicitações de reautenticação, chame acquireTokenSilent. Entretanto, há algumas situações em que talvez seja necessário forçar os usuários a interagir com a plataforma de identidade da Microsoft. Por exemplo:

  • Os usuários precisam reinserir suas credenciais, pois a senha expirou.
  • Seu aplicativo está solicitando acesso a um recurso e você precisa do consentimento do usuário.
  • A autenticação de dois fatores é necessária.

Chamar acquireTokenPopup abre uma janela pop-up (ou acquireTokenRedirect redireciona usuários à plataforma de identidade da Microsoft). Nessa janela, os usuários precisam interagir confirmando suas credenciais, concedendo consentimento ao recurso necessário ou concluindo a autenticação de dois fatores.

Obter um token de usuário no modo silencioso

O método acquireTokenSilent manipula a aquisição e a renovação de tokens sem nenhuma interação do usuário. Após loginPopup (ou loginRedirect) ser executado pela primeira vez, acquireTokenSilent é o método usado normalmente para obter tokens usados para acessar recursos protegidos nas próximas chamadas. (Chamadas para solicitar ou renovar tokens são feitas de modo silencioso.) acquireTokenSilent pode falhar em alguns casos. Por exemplo, a senha do usuário pode ter expirado. O aplicativo pode tratar essa exceção de duas maneiras:

  1. Fazer uma chamada para acquireTokenPopup imediatamente, o que dispara um prompt de entrada do usuário. Esse padrão é usado frequentemente em aplicativos online em que não há nenhum conteúdo não autenticado no aplicativo disponível para o usuário. O exemplo gerado por essa instalação guiada usa esse padrão.
  2. Indicar visualmente ao usuários que uma conexão interativa é necessária e, portanto, o usuário pode escolher o momento certo para se conectar ou o aplicativo pode tentar acquireTokenSilent novamente mais tarde. Essa técnica normalmente é usada quando o usuário pode usar outra funcionalidade do aplicativo sem ser interrompido. Por exemplo, pode haver conteúdo não autenticado disponível no aplicativo. Nessa situação, o usuário pode decidir quando deseja entrar para acessar o recurso protegido ou para atualizar as informações desatualizadas.

Observação

Este tutorial usa os métodos loginPopup e acquireTokenPopup por padrão. Se você está usando o Internet Explorer, recomendamos que use os métodos loginRedirect e acquireTokenRedirect devido a um problema conhecido com o Internet Explorer e janelas pop-up. Para ver um exemplo de como obter o mesmo resultado usando métodos de redirecionamento, confira authRedirect.js no GitHub.

Chamar a API do Microsoft Graph

Crie um arquivo chamado graph.js na pasta app e adicione o código a seguir para fazer chamadas REST para a API do Microsoft Graph:

/** 
 * Helper function to call MS Graph API endpoint
 * using the authorization bearer token scheme
*/
function callMSGraph(endpoint, token, callback) {
    const headers = new Headers();
    const bearer = `Bearer ${token}`;

    headers.append("Authorization", bearer);

    const options = {
        method: "GET",
        headers: headers
    };

    console.log('request made to Graph API at: ' + new Date().toString());

    fetch(endpoint, options)
        .then(response => response.json())
        .then(response => callback(response, endpoint))
        .catch(error => console.log(error));
}

No aplicativo de exemplo criado por este tutorial, o método callMSGraph() é usado para fazer uma solicitação HTTP GET em um recurso protegido que exige um token. Depois, a solicitação retorna o conteúdo para o chamador. Esse método adiciona o token adquirido no cabeçalho de Autorização HTTP. No aplicativo de exemplo criado neste tutorial, o recurso protegido é o ponto de extremidade me da API do Microsoft Graph, que exibe as informações de perfil do usuário conectado.

Teste seu aplicativo

Você concluiu a criação do aplicativo e agora está pronto para iniciar o servidor Web Node.js e testar a funcionalidade do aplicativo.

  1. Inicie o servidor Web Node.js executando o seguinte comando de dentro da raiz da pasta do aplicativo:

    npm start
    
  2. No navegador, navegue até http://localhost:3000 ou http://localhost:<port>, em que <port> é a porta na qual o servidor Web está escutando. Você deve ver o conteúdo do seu arquivo index.html e o botão Entrar.

Entrar no aplicativo

Depois que o navegador carregar seu arquivo index.html, selecione Entrar. Você deverá entrar na plataforma de identidade da Microsoft:

Web browser displaying sign-in dialog

Na primeira vez que entrar no aplicativo, você será solicitado a conceder acesso ao seu perfil e a conectá-lo:

Content dialog displayed in web browser

Se você concordar com as permissões solicitadas, os aplicativos Web exibirão seu nome de usuário, indicando um logon bem-sucedido:

Results of a successful sign-in in the web browser

Chamar a API do Graph

Depois de entrar, selecione Ver Perfil para exibir as informações do perfil do usuário retornadas na resposta da chamada à API do Microsoft Graph:

Profile information from Microsoft Graph displayed in the browser

Mais informações sobre escopos e permissões delegadas

A API do Microsoft Graph requer o escopo user.read para ler o perfil do usuário. Por padrão, esse escopo é adicionado automaticamente em todos os aplicativos registrados no Centro de administração do Microsoft Entra. Outras APIs do Microsoft Graph, bem como APIs personalizadas do servidor de back-end, podem exigir escopos adicionais. Por exemplo, a API do Microsoft Graph requer o escopo Mail.Read para listar o email do usuário.

À medida que você adiciona escopos, os usuários podem ser solicitados a fornecer consentimento adicional para os escopos adicionados.

Se uma API de back-end não exigir um escopo, o que não é recomendado, você poderá usar clientId como o escopo nas chamadas para obter tokens.

Ajuda e suporte

Se precisar de ajuda, quiser relatar um problema ou desejar saber mais sobre as opções de suporte, confira Ajuda e suporte para desenvolvedores.

Próximas etapas

  • Saiba mais criando um Aplicativo de Página Única (SPA) React que conecta usuários na série de tutoriais de várias partes a seguir.