Aktifkan autentikasi di aplikasi web Node Anda sendiri menggunakan Azure Active Directory B2C

Pada artikel ini, Anda akan mempelajari cara menambahkan autentikasi Azure Active Directory B2C (Azure AD B2C) di aplikasi web Node.js Anda sendiri. Anda akan mengizinkan pengguna untuk masuk, keluar, memperbarui profil, dan mengatur ulang kata sandi menggunakan alur pengguna Azure AD B2C. Artikel ini menggunakan Microsoft Authentication Library (MSAL) untuk Node untuk menyederhanakan penambahan autentikasi ke aplikasi web node Anda.

Tujuan artikel ini adalah untuk mengganti contoh aplikasi yang Anda gunakan dalam Mengonfigurasi autentikasi dalam contoh aplikasi web Node.js dengan menggunakan Azure AD B2C dengan aplikasi web Node.js Anda sendiri.

Artikel ini menggunakan Node.js dan Express untuk membuat aplikasi web Node.js dasar. Tampilan aplikasi menggunakan Handlebars.

Prasyarat

Langkah 1: Buat proyek node

Buat folder untuk menghosting aplikasi node Anda, seperti active-directory-b2c-msal-node-sign-in-sign-out-webapp.

  1. Di terminal Anda, ubah direktori ke folder aplikasi Node Anda, seperti cd active-directory-b2c-msal-node-sign-in-sign-out-webapp, dan jalankan npm init -y. Perintah ini membuat file package.json default untuk proyek Node.js Anda.

  2. Di terminal Anda, jalankan npm install express. Perintah ini menginstal kerangka kerja Express.

  3. Buat lebih banyak folder dan file untuk mendapatkan struktur proyek berikut:

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

Folder views berisi file Handlebars untuk antarmuka pengguna aplikasi.

Langkah 2: Memasang dependensi aplikasi

Di terminal Anda, pasang paket dotenv, express-handlebars, express-session, dan @azure/msal-node dengan menjalankan perintah berikut:

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

Langkah 3: Membangun komponen UI aplikasi

Dalam file main.hbs, tambahkan kode berikut:

<!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>

File main.hbs berada di folder layout. File tersebut harus berisi kode HTML yang diperlukan di seluruh aplikasi Anda. Setiap UI yang berubah dari satu tampilan ke tampilan lain, seperti di signin.hbs, ditempatkan di tempat penampung yang ditampilkan sebagai {{{body}}}.

File main.hbs mengimplementasikan antarmuka pengguna yang dibangun dengan kerangka kerja CSS Bootstrap 5. Anda akan melihat komponen antarmuka pengguna (tombol) Pengeditan kata sandi, Pengaturan ulang kata sandi, dan Keluar saat pengguna masuk. Anda akan melihat Masuk saat keluar. Perilaku ini dikontrol oleh showSignInButton variabel Boolean, yang dikirim oleh server aplikasi.

Dalam file signin.hbs, tambahkan kode berikut:

<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>

Langkah 4: Konfigurasi server web dan klien MSAL

  1. Dalam .env file, tambahkan kode berikut dan perbarui seperti yang dijelaskan dalam Konfigurasi sampel aplikasi 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. Di file index.js Anda, tambahkan kode berikut untuk menggunakan dependensi aplikasi Anda:

    require('dotenv').config();
    const express = require('express');
    const session = require('express-session');
    const {engine}  = require('express-handlebars');
    const msal = require('@azure/msal-node');
    
  3. Dalam index.js file Anda, tambahkan kode berikut untuk mengonfigurasi pustaka autentikasi:

    /**
     * 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 konfigurasi objek MSAL digunakan untuk terhubung ke titik akhir autentikasi penyewa AAD B2C Anda.

  4. Untuk menambahkan variabel global mode dalam index.js file, tambahkan kode berikut:

    /**
     * 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: Digunakan untuk membedakan antara tanggapan yang diterima dari Azure Active Directory B2C dengan menandai permintaan. Hanya ada satu pengalihan URI untuk berapa pun jumlah permintaan yang dikirim ke Azure AD B2C.
    2. authCodeRequest: Objek konfigurasi yang digunakan untuk mengambil kode otorisasi.
    3. tokenRequest: Objek konfigurasi yang digunakan untuk mendapatkan token dengan kode otorisasi.
    4. sessionConfig: Objek konfigurasi untuk sesi Ekspres.
  5. Untuk mengatur mesin templat tampilan dan konfigurasi sesi Ekspres, tambahkan kode berikut dalam file 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));
    

Langkah 5: Tambahkan rute ekspres

Sebelum Anda menambahkan rute aplikasi, tambahkan logika yang mengambil URL kode otorisasi, yang merupakan leg pertama alur pemberian kode otorisasi. Dalam file index.js, tambahkan kode berikut:


/**
 * 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);
        });
}

Objek authCodeRequest memiliki properti redirectUri, authority, scopes, dan state. Objek tersebut diteruskan ke metode getAuthCodeUrl sebagai parameter.

Dalam file index.js, tambahkan kode berikut:

 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!');
    }

});

Rute ekspres adalah:

  • /:
    • Digunakan untuk memasuki aplikasi web.
    • Merender halaman signin.
  • /signin:
    • Ini digunakan saat Anda masuk.
    • Objek memanggil metode getAuthCode() dan meneruskan authority untuk kebijakan/alur pengguna Daftar dan masuk, APP_STATES.LOGIN, dan mengosongkan array scopes.
    • Jika perlu, itu menyebabkan tantangan pada Anda untuk memasukkan kredensial Anda. Jika Anda tidak memiliki akun, akun tersebut akan meminta Anda untuk mendaftar.
    • Respons akhir yang dihasilkan dari titik akhir ini mencakup kode otorisasi dari Azure AD B2C yang diposting kembali ke /redirect titik akhir.
  • /password:
    • Ini digunakan saat Anda mengatur ulang kata sandi.
    • Objek memanggil metode getAuthCode() dan meneruskan authority untuk kebijakan/alur pengguna Pengaturan ulang kata sandi, APP_STATES.PASSWORD_RESET, dan mengosongkan array scopes.
    • Ini memungkinkan Anda untuk mengubah kata sandi Anda dengan menggunakan pengalaman mengatur ulang kata sandi, atau mereka dapat membatalkan operasi.
    • Respons akhir yang dihasilkan dari titik akhir ini mencakup kode otorisasi dari Azure AD B2C yang diposting kembali ke /redirect titik akhir. Jika Anda membatalkan operasi, kesalahan akan diposting kembali.
  • /profile:
    • Ini digunakan saat Anda memperbarui profil Anda.
    • Objek memanggil metode getAuthCode() dan melewati authority untuk kebijakan/alur pengguna Pengeditan profil, APP_STATES.EDIT_PROFILE, dan mengosongkan array scopes.
    • Ini memungkinkan Anda untuk memperbarui profil Anda, dan Anda menggunakan pengalaman mengedit profil.
    • Respons akhir yang dihasilkan dari titik akhir ini mencakup kode otorisasi dari Azure AD B2C yang diposting kembali ke /redirect titik akhir.
  • /signout:
    • Ini digunakan saat Anda keluar.
    • Aplikasi web menghapus sesi, dan melakukan panggilan HTTP ke titik akhir keluar Azure AD B2C.
  • /redirect:
    • Ini adalah rute yang ditetapkan sebagai URI Pengalihan untuk aplikasi web di portal Azure.
    • Ini menggunakan state parameter kueri dalam permintaan dari Azure AD B2C untuk membedakan antara permintaan yang dibuat dari aplikasi web. Ini menangani semua proses pengalihan dari Azure AD B2C, kecuali untuk keluar.
    • Jika status aplikasi adalah APP_STATES.LOGIN, kode otorisasi yang didapatkan akan digunakan untuk mengambil token melalui metode acquireTokenByCode(). Token ini mencakup idToken dan idTokenClaims, yang digunakan untuk identifikasi pengguna.
    • Jika status aplikasi adalah APP_STATES.PASSWORD_RESET, ia menangani kesalahan apa pun, seperti user cancelled the operation. AADB2C90091 Kode kesalahan mengidentifikasi kesalahan ini. Jika tidak, ia memutuskan pengalaman pengguna berikutnya.
    • Jika status aplikasi adalah APP_STATES.EDIT_PROFILE, kode otorisasi akan digunakan untuk mendapatkan token. Token berisi idTokenClaims, yang mencakup perubahan baru.

Langkah 6: Mulai server Node

Untuk memulai server Node, tambahkan kode berikut dalam file index.js:

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

Setelah Anda membuat semua perubahan yang diperlukan dalam index.js file, itu akan terlihat mirip dengan file berikut:

/*
 * 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>

Langkah 7: Jalankan aplikasi web Anda

Ikuti langkah-langkah di Jalankan aplikasi web Anda untuk menguji aplikasi web Node.js Anda.

Langkah berikutnya