Partager via


Activer l’authentification dans votre propre application web Node à l’aide d’Azure Active Directory B2C

Dans cet article, vous allez apprendre à ajouter l’authentification Azure Active Directory B2C (Azure AD B2C) dans votre propre application web Node.js. Vous permettez aux utilisateurs de se connecter, de se déconnecter, de mettre à jour leur profil et de réinitialiser leur mot de passe à l’aide des flux d’utilisateurs Azure AD B2C. Cet article utilise la bibliothèque d’authentification Microsoft (MSAL) pour Node afin de simplifier l’ajout de l’authentification à votre application web Node.

L’objectif de cet article est de remplacer l’exemple d’application que vous avez utilisé dans Configurer l’authentification dans un exemple d’application web Node.js à l’aide d’Azure AD B2C par votre propre application web Node.js.

Cet article utilise Node.js et Express pour créer une application web Node.js de base. Les vues de l’application utilisent Handlebars.

Prérequis

Étape 1 : créer le projet Node

Créez un dossier pour héberger votre application Node, par exemple active-directory-b2c-msal-node-sign-in-sign-out-webapp.

  1. Dans votre terminal, accédez à un répertoire dans votre dossier d’application Node, par exemple cd active-directory-b2c-msal-node-sign-in-sign-out-webapp, et exécutez npm init -y. Cette commande crée un fichier package.json par défaut pour votre projet Node.js.

  2. Dans votre terminal, exécutez npm install express. Cette commande installe le framework Express.

  3. Créez d’autres dossiers et fichiers pour obtenir la structure de projet suivante :

    active-directory-b2c-msal-node-sign-in-sign-out-webapp/
    ├── index.js
    └── package.json
    └── .env
    └── views/
        └── layouts/
            └── main.hbs
        └── signin.hbs
    

Le dossier views contient des fichiers Handlebars pour l’interface utilisateur de l’application.

Étape 2 : installer les dépendances d’application

Dans votre terminal, installez les packages dotenv, express-handlebars, express-session et @azure/msal-node en exécutant les commandes suivantes :

npm install dotenv
npm install express-handlebars
npm install express-session
npm install @azure/msal-node

Étape 3 : générer les composants de l’interface utilisateur de l’application

Dans le fichier main.hbs, ajoutez le code suivant :

<!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>Tutorial | Authenticate users with MSAL for B2C</title>

    <!-- adding Bootstrap 4 for UI components  -->
    <!-- CSS only -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" 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>
        {{#if showSignInButton}}
            <div class="ml-auto">
                <a type="button" id="SignIn" class="btn btn-secondary" href="/signin" aria-haspopup="true" aria-expanded="false">
                    Sign in
                </a>
            </div>
        {{else}}
              <div class="ml-auto">
                  <a type="button" id="EditProfile" class="btn btn-warning" href="/profile" aria-haspopup="true" aria-expanded="false">
                      Edit profile
                  </a>
                  <a type="button" id="PasswordReset" class="btn btn-warning" href="/password" aria-haspopup="true" aria-expanded="false">
                      Reset password
                  </a>
              </div>

                <p class="navbar-brand d-flex ms-auto">Hi {{givenName}}</p>

                <a class="navbar-brand d-flex ms-auto" href="/signout">Sign out</a>
        {{/if}}
    </nav>
    <br>
    <h5 class="card-header text-center">MSAL Node Confidential Client application with Auth Code Flow</h5>
    <br>
    <div class="row" style="margin:auto" >
      {{{body}}}
    </div>
    <br>
    <br>
  </body>
</html>

Le fichier main.hbs se trouve dans le dossier layout. Il doit contenir tout code HTML requis dans votre application. Toute interface utilisateur passant d’une vue à une autre, comme dans signin.hbs, est placée dans l’espace réservé indiqué sous la forme de {{{body}}}.

Le fichier main.hbs implémente l’interface utilisateur générée avec l’infrastructure CSS Bootstrap 5. Vous voyez les composants Modifier le mot de passe, Réinitialiser le mot de passe et Se déconnecter (boutons) de l’interface utilisateur quand vous êtes connecté. Vous voyez Se connecter lorsque vous êtes déconnecté. Ce comportement est contrôlé par la variable booléenne showSignInButton que le serveur d’applications envoie.

Dans le fichier signin.hbs, ajoutez le code suivant :

<div class="col-md-3" style="margin:auto">
  <div class="card text-center">
    <div class="card-body">
      {{#if showSignInButton}}
          <h5 class="card-title">Please sign-in to acquire an ID token</h5>
      {{else}}
           <h5 class="card-title">You have signed in</h5>
      {{/if}}
    </div>

    <div class="card-body">
      {{#if message}}
          <h5 class="card-title text-danger">{{message}}</h5>
      {{/if}}
    </div>
  </div>
</div>

Étape 4 : configurer le serveur web et le client MSAL

  1. Dans le fichier .env, ajoutez le code suivant et mettez-le à jour comme indiqué dans Configurer l’exemple d’application web.

    #HTTP port
    SERVER_PORT=3000
    #web apps client ID
    APP_CLIENT_ID=<You app client ID here>
    #session secret
    SESSION_SECRET=sessionSecretHere
    #web app client secret
    APP_CLIENT_SECRET=<Your app client secret here>
    #B2C sign up and sign in user flow/policy authority
    SIGN_UP_SIGN_IN_POLICY_AUTHORITY=https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<sign-in-sign-up-user-flow-name>
    #B2C password reset user flow/policy authority
    RESET_PASSWORD_POLICY_AUTHORITY=https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<reset-password-user-flow-name>
    #B2C edit profile user flow/policy authority
    EDIT_PROFILE_POLICY_AUTHORITY=https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<profile-edit-user-flow-name>
    #B2C authority domain
    AUTHORITY_DOMAIN=https://<your-tenant-name>.b2clogin.com
    #client redirect url
    APP_REDIRECT_URI=http://localhost:3000/redirect
    #Logout endpoint 
    LOGOUT_ENDPOINT=https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<sign-in-sign-up-user-flow-name>/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000
    
  2. Dans votre fichier index.js, ajoutez le code suivant pour utiliser les dépendances de votre application :

    require('dotenv').config();
    const express = require('express');
    const session = require('express-session');
    const {engine}  = require('express-handlebars');
    const msal = require('@azure/msal-node');
    
  3. Dans votre fichier index.js, ajoutez le code suivant pour configurer la bibliothèque d’authentification :

    /**
     * Confidential Client Application Configuration
     */
     const confidentialClientConfig = {
        auth: {
            clientId: process.env.APP_CLIENT_ID, 
            authority: process.env.SIGN_UP_SIGN_IN_POLICY_AUTHORITY, 
            clientSecret: process.env.APP_CLIENT_SECRET,
            knownAuthorities: [process.env.AUTHORITY_DOMAIN], //This must be an array
            redirectUri: process.env.APP_REDIRECT_URI,
            validateAuthority: false
        },
        system: {
            loggerOptions: {
                loggerCallback(loglevel, message, containsPii) {
                    console.log(message);
                },
                piiLoggingEnabled: false,
                logLevel: msal.LogLevel.Verbose,
            }
        }
    };
    
    // Initialize MSAL Node
    const confidentialClientApplication = new msal.ConfidentialClientApplication(confidentialClientConfig);
    

    confidentialClientConfig est l’objet de configuration MSAL utilisé pour la connexion aux points de terminaison d’authentification de votre locataire Azure AD B2C.

  4. Pour ajouter des variables globales de mode dans le fichier index.js, ajoutez le code suivant :

    /**
     * The MSAL.js library allows you to pass your custom state as state parameter in the Request object
     * By default, MSAL.js passes a randomly generated unique state parameter value in the authentication requests.
     * The state parameter can also be used to encode information of the app's state before redirect. 
     * You can pass the user's state in the app, such as the page or view they were on, as input to this parameter.
     * For more information, visit: https://docs.microsoft.com/azure/active-directory/develop/msal-js-pass-custom-state-authentication-request
     * In this scenario, the states also serve to show the action that was requested of B2C since only one redirect URL is possible. 
     */
    
    const APP_STATES = {
        LOGIN: 'login',
        LOGOUT: 'logout',
        PASSWORD_RESET: 'password_reset',
        EDIT_PROFILE : 'update_profile'
    }
    
    
    /** 
     * Request Configuration
     * We manipulate these two request objects below 
     * to acquire a token with the appropriate claims.
     */
     const authCodeRequest = {
        redirectUri: confidentialClientConfig.auth.redirectUri,
    };
    
    const tokenRequest = {
        redirectUri: confidentialClientConfig.auth.redirectUri,
    };
    
    /**
     * Using express-session middleware. Be sure to familiarize yourself with available options
     * and set them as desired. Visit: https://www.npmjs.com/package/express-session
     */
     const sessionConfig = {
        secret: process.env.SESSION_SECRET,
        resave: false,
        saveUninitialized: false,
        cookie: {
            secure: false, // set this to true on production
        }
    }
    
    1. APP_STATES: Permet de faire la distinction entre les réponses reçues de Azure AD B2C en marquant les demandes. Il n’existe qu’un seul URI de redirection pour un nombre quelconque de demandes envoyées à Azure AD B2C.
    2. authCodeRequest : objet de configuration utilisé pour récupérer le code d’autorisation.
    3. tokenRequest : objet de configuration utilisé pour acquérir un jeton par code d’autorisation.
    4. sessionConfig : objet de configuration pour la session Express.
  5. Pour définir le moteur de modèle d’affichage et la configuration de session Express, ajoutez le code suivant dans le fichier index.js :

     
    //Create an express instance
    const app = express();
    
    //Set handlebars as your view engine
    app.engine('.hbs', engine({extname: '.hbs'}));
    app.set('view engine', '.hbs');
    app.set("views", "./views");
    
    //usse session configuration 
    app.use(session(sessionConfig));
    

Étape 5 : ajouter des itinéraires Express

Avant d’ajouter l’itinéraire de l’application, ajoutez la logique qui récupère l’URL du code d’autorisation, qui est la première partie du flux d’octroi du code d’autorisation. Dans le fichier index.js, ajoutez le code suivant :


/**
 * This method is used to generate an auth code request
 * @param {string} authority: the authority to request the auth code from 
 * @param {array} scopes: scopes to request the auth code for 
 * @param {string} state: state of the application
 * @param {Object} res: express middleware response object
 */
 const getAuthCode = (authority, scopes, state, res) => {

    // prepare the request
    console.log("Fetching Authorization code")
    authCodeRequest.authority = authority;
    authCodeRequest.scopes = scopes;
    authCodeRequest.state = state;

    //Each time you fetch Authorization code, update the relevant authority in the tokenRequest configuration
    tokenRequest.authority = authority;

    // request an authorization code to exchange for a token
    return confidentialClientApplication.getAuthCodeUrl(authCodeRequest)
        .then((response) => {
            console.log("\nAuthCodeURL: \n" + response);
            //redirect to the auth code URL/send code to 
            res.redirect(response);
        })
        .catch((error) => {
            res.status(500).send(error);
        });
}

L’objet authCodeRequest dispose des propriétés redirectUri, authority, scopes et state. L’objet est passé à la méthode getAuthCodeUrl en tant que paramètre.

Dans le fichier index.js, ajoutez le code suivant :

 app.get('/', (req, res) => {
    res.render('signin', { showSignInButton: true });
});

app.get('/signin',(req, res)=>{
        //Initiate a Auth Code Flow >> for sign in
        //no scopes passed. openid, profile and offline_access will be used by default.
        getAuthCode(process.env.SIGN_UP_SIGN_IN_POLICY_AUTHORITY, [], APP_STATES.LOGIN, res);
});

/**
 * Change password end point
*/
app.get('/password',(req, res)=>{
    getAuthCode(process.env.RESET_PASSWORD_POLICY_AUTHORITY, [], APP_STATES.PASSWORD_RESET, res); 
});

/**
 * Edit profile end point
*/
app.get('/profile',(req, res)=>{
    getAuthCode(process.env.EDIT_PROFILE_POLICY_AUTHORITY, [], APP_STATES.EDIT_PROFILE, res); 
});

/**
 * Sign out end point
*/
app.get('/signout',async (req, res)=>{    
    logoutUri = process.env.LOGOUT_ENDPOINT;
    req.session.destroy(() => {
        //When session destruction succeeds, notify B2C service using the logout uri.
        res.redirect(logoutUri);
    });
});

app.get('/redirect',(req, res)=>{
    
    //determine the reason why the request was sent by checking the state
    if (req.query.state === APP_STATES.LOGIN) {
        //prepare the request for authentication        
        tokenRequest.code = req.query.code;
        confidentialClientApplication.acquireTokenByCode(tokenRequest).then((response)=>{
        
        req.session.sessionParams = {user: response.account, idToken: response.idToken};
        console.log("\nAuthToken: \n" + JSON.stringify(response));
        res.render('signin',{showSignInButton: false, givenName: response.account.idTokenClaims.given_name});
        }).catch((error)=>{
            console.log("\nErrorAtLogin: \n" + error);
        });
    }else if (req.query.state === APP_STATES.PASSWORD_RESET) {
        //If the query string has a error param
        if (req.query.error) {
            //and if the error_description contains AADB2C90091 error code
            //Means user selected the Cancel button on the password reset experience 
            if (JSON.stringify(req.query.error_description).includes('AADB2C90091')) {
                //Send the user home with some message
                //But always check if your session still exists
                res.render('signin', {showSignInButton: false, givenName: req.session.sessionParams.user.idTokenClaims.given_name, message: 'User has cancelled the operation'});
            }
        }else{
            
            res.render('signin', {showSignInButton: false, givenName: req.session.sessionParams.user.idTokenClaims.given_name});
        }        
        
    }else if (req.query.state === APP_STATES.EDIT_PROFILE){
    
        tokenRequest.scopes = [];
        tokenRequest.code = req.query.code;
        
        //Request token with claims, including the name that was updated.
        confidentialClientApplication.acquireTokenByCode(tokenRequest).then((response)=>{
            req.session.sessionParams = {user: response.account, idToken: response.idToken};
            console.log("\AuthToken: \n" + JSON.stringify(response));
            res.render('signin',{showSignInButton: false, givenName: response.account.idTokenClaims.given_name});
        }).catch((error)=>{
            //Handle error
        });
    }else{
        res.status(500).send('We do not recognize this response!');
    }

});

Les itinéraires Express sont les suivants :

  • /:
    • Utilisé pour accéder à l’application web.
    • Affiche la page signin.
  • /signin:
    • Utilisé lorsque vous vous connectez.
    • Appelle la méthode getAuthCode() et lui passe authority pour le flux ou la stratégie utilisateur Inscription et connexion, APP_STATES.LOGIN, et un tableau scopes vide.
    • Si nécessaire, vous devez entrer vos informations d’identification. Si vous n’avez pas de compte, vous êtes invité à vous inscrire.
    • La réponse finale résultant de cet itinéraire comprend un code d’autorisation d’Azure AD B2C retourné à l’itinéraire /redirect.
  • /password:
    • Utilisé lorsque vous réinitialisez un mot de passe.
    • Appelle la méthode getAuthCode() et lui passe authority pour le flux ou la stratégie utilisateur Réinitialisation du mot de passe, APP_STATES.PASSWORD_RESET, et un tableau scopes vide.
    • Permet de modifier votre mot de passe à l’aide de l’expérience de réinitialisation du mot de passe, ou d’annuler l’opération.
    • La réponse finale résultant de cet itinéraire comprend un code d’autorisation d’Azure AD B2C retourné à l’itinéraire /redirect. Si vous annulez l’opération, une erreur est retournée.
  • /profile:
    • Utilisé lorsque vous mettez à jour votre profil.
    • Appelle la méthode getAuthCode() et lui passe authority pour le flux ou la stratégie utilisateur Modification du profil, APP_STATES.EDIT_PROFILE, et un tableau scopes vide.
    • Permet de mettre à jour votre profil et d’utiliser l’expérience de modification de profil.
    • La réponse finale résultant de cet itinéraire comprend un code d’autorisation d’Azure AD B2C retourné à l’itinéraire /redirect.
  • /signout:
    • Utilisé lorsque vous vous déconnectez.
    • L’application web efface la session et effectue un appel HTTP au point de terminaison de déconnexion d’Azure AD B2C.
  • /redirect:
    • Itinéraire défini en tant qu’URI de redirection pour l’application web dans le Portail Azure.
    • Utilise le paramètre de requête state dans la demande d’Azure AD B2C pour différencier les demandes effectuées à partir de l’application web. Gère toutes les redirections à partir d’Azure AD B2C, à l’exception de la déconnexion.
    • Si l’état de l’application est APP_STATES.LOGIN, le code d’autorisation acquis est utilisé pour récupérer un jeton via la méthode acquireTokenByCode(). Ce jeton inclut idToken et idTokenClaims, qui sont utilisés pour l’identification de l’utilisateur.
    • Si l’état de l’application est APP_STATES.PASSWORD_RESET, elle gère toutes les erreurs, telles que user cancelled the operation. Le code d’erreur AADB2C90091 identifie cette erreur. Dans le cas contraire, il décide de l’expérience utilisateur suivante.
    • Si l’état de l’application est APP_STATES.EDIT_PROFILE, il utilise le code d’autorisation pour acquérir un jeton. Le jeton contient idTokenClaims, qui inclut les nouvelles modifications.

Étape 6 : démarrer le serveur Node

Pour démarrer le serveur Node, ajoutez le code suivant dans le fichier index.js :

app.listen(process.env.SERVER_PORT, () => {
    console.log(`Msal Node Auth Code Sample app listening on port !` + process.env.SERVER_PORT);
});

Une fois que vous avez apporté toutes les modifications requises dans le fichier index.js, il doit ressembler à ce qui suit :

/*
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */
 //<ms_docref_use_app_dependencies>
require('dotenv').config();
const express = require('express');
const session = require('express-session');
const {engine}  = require('express-handlebars');
const msal = require('@azure/msal-node');
//</ms_docref_use_app_dependencies>

//<ms_docref_configure_msal>
/**
 * Confidential Client Application Configuration
 */
 const confidentialClientConfig = {
    auth: {
        clientId: process.env.APP_CLIENT_ID, 
        authority: process.env.SIGN_UP_SIGN_IN_POLICY_AUTHORITY, 
        clientSecret: process.env.APP_CLIENT_SECRET,
        knownAuthorities: [process.env.AUTHORITY_DOMAIN], //This must be an array
        redirectUri: process.env.APP_REDIRECT_URI,
        validateAuthority: false
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: msal.LogLevel.Verbose,
        }
    }
};

// Initialize MSAL Node
const confidentialClientApplication = new msal.ConfidentialClientApplication(confidentialClientConfig);
//</ms_docref_configure_msal>

//<ms_docref_global_variable>
/**
 * The MSAL.js library allows you to pass your custom state as state parameter in the Request object
 * By default, MSAL.js passes a randomly generated unique state parameter value in the authentication requests.
 * The state parameter can also be used to encode information of the app's state before redirect. 
 * You can pass the user's state in the app, such as the page or view they were on, as input to this parameter.
 * For more information, visit: https://docs.microsoft.com/azure/active-directory/develop/msal-js-pass-custom-state-authentication-request
 * In this scenario, the states also serve to show the action that was requested of B2C since only one redirect URL is possible. 
 */

const APP_STATES = {
    LOGIN: 'login',
    LOGOUT: 'logout',
    PASSWORD_RESET: 'password_reset',
    EDIT_PROFILE : 'update_profile'
}


/** 
 * Request Configuration
 * We manipulate these two request objects below 
 * to acquire a token with the appropriate claims.
 */
 const authCodeRequest = {
    redirectUri: confidentialClientConfig.auth.redirectUri,
};

const tokenRequest = {
    redirectUri: confidentialClientConfig.auth.redirectUri,
};

/**
 * Using express-session middleware. Be sure to familiarize yourself with available options
 * and set them as desired. Visit: https://www.npmjs.com/package/express-session
 */
 const sessionConfig = {
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: {
        secure: false, // set this to true on production
    }
}

//</ms_docref_global_variable>

//<ms_docref_view_tepmplate_engine>
 
//Create an express instance
const app = express();

//Set handlebars as your view engine
app.engine('.hbs', engine({extname: '.hbs'}));
app.set('view engine', '.hbs');
app.set("views", "./views");

//usse session configuration 
app.use(session(sessionConfig));

//</ms_docref_view_tepmplate_engine>

//<ms_docref_authorization_code_url>

/**
 * This method is used to generate an auth code request
 * @param {string} authority: the authority to request the auth code from 
 * @param {array} scopes: scopes to request the auth code for 
 * @param {string} state: state of the application
 * @param {Object} res: express middleware response object
 */
 const getAuthCode = (authority, scopes, state, res) => {

    // prepare the request
    console.log("Fetching Authorization code")
    authCodeRequest.authority = authority;
    authCodeRequest.scopes = scopes;
    authCodeRequest.state = state;

    //Each time you fetch Authorization code, update the relevant authority in the tokenRequest configuration
    tokenRequest.authority = authority;

    // request an authorization code to exchange for a token
    return confidentialClientApplication.getAuthCodeUrl(authCodeRequest)
        .then((response) => {
            console.log("\nAuthCodeURL: \n" + response);
            //redirect to the auth code URL/send code to 
            res.redirect(response);
        })
        .catch((error) => {
            res.status(500).send(error);
        });
}
 
 //</ms_docref_authorization_code_url>

 
 //<ms_docref_app_endpoints>
 app.get('/', (req, res) => {
    res.render('signin', { showSignInButton: true });
});

app.get('/signin',(req, res)=>{
        //Initiate a Auth Code Flow >> for sign in
        //no scopes passed. openid, profile and offline_access will be used by default.
        getAuthCode(process.env.SIGN_UP_SIGN_IN_POLICY_AUTHORITY, [], APP_STATES.LOGIN, res);
});

/**
 * Change password end point
*/
app.get('/password',(req, res)=>{
    getAuthCode(process.env.RESET_PASSWORD_POLICY_AUTHORITY, [], APP_STATES.PASSWORD_RESET, res); 
});

/**
 * Edit profile end point
*/
app.get('/profile',(req, res)=>{
    getAuthCode(process.env.EDIT_PROFILE_POLICY_AUTHORITY, [], APP_STATES.EDIT_PROFILE, res); 
});

/**
 * Sign out end point
*/
app.get('/signout',async (req, res)=>{    
    logoutUri = process.env.LOGOUT_ENDPOINT;
    req.session.destroy(() => {
        //When session destruction succeeds, notify B2C service using the logout uri.
        res.redirect(logoutUri);
    });
});

app.get('/redirect',(req, res)=>{
    
    //determine the reason why the request was sent by checking the state
    if (req.query.state === APP_STATES.LOGIN) {
        //prepare the request for authentication        
        tokenRequest.code = req.query.code;
        confidentialClientApplication.acquireTokenByCode(tokenRequest).then((response)=>{
        
        req.session.sessionParams = {user: response.account, idToken: response.idToken};
        console.log("\nAuthToken: \n" + JSON.stringify(response));
        res.render('signin',{showSignInButton: false, givenName: response.account.idTokenClaims.given_name});
        }).catch((error)=>{
            console.log("\nErrorAtLogin: \n" + error);
        });
    }else if (req.query.state === APP_STATES.PASSWORD_RESET) {
        //If the query string has a error param
        if (req.query.error) {
            //and if the error_description contains AADB2C90091 error code
            //Means user selected the Cancel button on the password reset experience 
            if (JSON.stringify(req.query.error_description).includes('AADB2C90091')) {
                //Send the user home with some message
                //But always check if your session still exists
                res.render('signin', {showSignInButton: false, givenName: req.session.sessionParams.user.idTokenClaims.given_name, message: 'User has cancelled the operation'});
            }
        }else{
            
            res.render('signin', {showSignInButton: false, givenName: req.session.sessionParams.user.idTokenClaims.given_name});
        }        
        
    }else if (req.query.state === APP_STATES.EDIT_PROFILE){
    
        tokenRequest.scopes = [];
        tokenRequest.code = req.query.code;
        
        //Request token with claims, including the name that was updated.
        confidentialClientApplication.acquireTokenByCode(tokenRequest).then((response)=>{
            req.session.sessionParams = {user: response.account, idToken: response.idToken};
            console.log("\AuthToken: \n" + JSON.stringify(response));
            res.render('signin',{showSignInButton: false, givenName: response.account.idTokenClaims.given_name});
        }).catch((error)=>{
            //Handle error
        });
    }else{
        res.status(500).send('We do not recognize this response!');
    }

});

 //</ms_docref_app_endpoints>
//start app server to listen on set port
 //<ms_docref_start_node_server>
app.listen(process.env.SERVER_PORT, () => {
    console.log(`Msal Node Auth Code Sample app listening on port !` + process.env.SERVER_PORT);
});
//</ms_docref_start_node_server>

Étape 7 : exécuter votre application web

Suivez les étapes de la section Exécuter votre application web pour tester votre application web Node.js.

Étapes suivantes