チュートリアル: Vanilla JavaScript SPA で認証フローを処理する

このチュートリアルは、Vanilla JavaScript (JS) シングルページ アプリケーション (SPA) を構築して、認証のための準備をする方法を示すシリーズのパート 3 です。 このシリーズのパート 2 では、Vanilla JS SPA を作成し、外部テナントでの認証用に準備しました。 このチュートリアルでは、Microsoft Authentication Library (MSAL) コンポーネントを追加することで、アプリの認証フローを処理する方法について説明します。

このチュートリアルでは、

  • アプリケーションの設定を構成する
  • authRedirect.js にコードを追加して認証フローを処理する
  • authPopup.js にコードを追加して認証フローを処理する

前提条件

認証構成ファイルを編集する

  1. Public/authConfig.js を開き、次のコード スニペットを追加します。

    import { LogLevel } from '@azure/msal-browser';
    
    /**
    * 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 
    */
    
    export const msalConfig = {
        auth: {
            clientId: 'Enter_the_Application_Id_Here', // This is the ONLY mandatory field that you need to supply.
            authority: 'https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/', // Replace the placeholder with your tenant subdomain 
            redirectUri: '/', // Points to window.location.origin. You must register this URI on Azure Portal/App Registration.
            postLogoutRedirectUri: '/', // Indicates the page to navigate after logout.
            navigateToLoginRequestUrl: false, // If "true", will navigate back to the original request location before processing the auth code response.
        },
        cache: {
            cacheLocation: 'sessionStorage', // Configures cache location. "sessionStorage" is more secure, but "localStorage" gives you SSO between tabs.
            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 LogLevel.Error:
                            console.error(message);
                            return;
                        case LogLevel.Info:
                            console.info(message);
                            return;
                        case LogLevel.Verbose:
                            console.debug(message);
                            return;
                        case LogLevel.Warning:
                            console.warn(message);
                            return;
                        default:
                            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
    */
    export const loginRequest = {
        scopes: [],
    };
    
  2. 次の値を、Azure portal の値に置き換えます。

    • Enter_the_Application_Id_Here の値を見つけ、Microsoft Entra 管理センターで登録したアプリのアプリケーション ID (clientId) に置き換えます。
      • [権限] で、Enter_the_Tenant_Subdomain_Here を見つけ、それをテナントのサブドメインに置き換えます。 たとえば、テナントのプライマリ ドメインが contoso.onmicrosoft.com の場合は、contoso を使用します。 テナント名がない場合は、テナントの詳細を読み取る方法を確認してください
  3. ファイルを保存します。

カスタム URL ドメインを使用する (省略可能)

カスタム ドメインを使用して、認証 URL を完全にブランド化します。 ユーザーの視点から見ると、認証プロセスの間、ユーザーは ciamlogin.com ドメイン名にリダイレクトされず、あなたのドメインにとどまります。

カスタム ドメインを使用するには、以下の手順を実行します。

  1. 外部テナント内のアプリに対するカスタム URL ドメインの有効化」の手順を使用し、外部テナントに対してカスタム URL ドメインを有効にします。

  2. authConfig.js ファイルで、auth オブジェクトを見つけて、次のようにします。

    1. authority プロパティの値を https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here に更新します。 Enter_the_Custom_Domain_Here を実際のカスタム URL ドメインに、Enter_the_Tenant_ID_Here を実際のテナント ID に置き換えます。 テナント ID がわからない場合は、テナントの詳細を読み取る方法を確認してください。
    2. [Enter_the_Custom_Domain_Here] という値を持つ knownAuthorities プロパティを追加します。

たとえば、カスタム URL ドメインが login.contoso.com で、テナント ID が aaaabbbb-0000-cccc-1111-dddd2222eeee である場合、authConfig.js ファイルに変更を加えた結果の内容は以下のようになります。

//...
const msalConfig = {
    auth: {
        authority: process.env.AUTHORITY || 'https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee', 
        knownAuthorities: ["login.contoso.com"],
        //Other properties
    },
    //...
};

リダイレクト ファイルにコードを追加する

サインイン ページからの応答を処理するには、リダイレクト ファイルが必要です。 これは、URL フラグメントからアクセス トークンを抽出し、それを使用して保護された API を呼び出すために使用されます。 また、認証プロセス中に発生するエラーを処理するためにも使用されます。

  1. public/authRedirect.js を開き、次のコード スニペットを追加します。

    // 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/initialization.md#redirect-apis
    */
    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) {
            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
            welcomeUser(currentAccounts[0].username);
            updateTable(currentAccounts[0]);
        }
    }
    
    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
            welcomeUser(username);
            updateTable(response.account);
        } 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
        */
    
        // Choose which account to logout from by passing a username.
        const logoutRequest = {
            account: myMSALObj.getAccountByUsername(username),
            postLogoutRedirectUri: '/signout', // remove this line if you would like navigate to index page after logout.
    
        };
    
        myMSALObj.logoutRedirect(logoutRequest);
    }
    
  2. ファイルを保存します。

authPopup.js ファイルにコードを追加する

ユーザーがポップアップ ウィンドウを使用してサインインする場合、アプリケーションでは authPopup.js を使用して認証フローを処理します。 ポップアップ ウィンドウは、ユーザーが既にサインインしていて、アプリケーションで別のリソースのアクセス トークンを取得する必要がある場合に使用されます。

  1. public/authPopup.js を開き、次のコード スニペットを追加します。

    // 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  || currentAccounts.length < 1) {
            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
            welcomeUser(currentAccounts[0].username);
            updateTable(currentAccounts[0]);
        }
    }
    
    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
            welcomeUser(username);
            updateTable(response.account);
        } 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
         */
    
        // Choose which account to logout from by passing a username.
        const logoutRequest = {
            account: myMSALObj.getAccountByUsername(username),
            mainWindowRedirectUri: '/signout'
        };
    
        myMSALObj.logoutPopup(logoutRequest);
    }
    
    selectAccount();
    
  2. ファイルを保存します。

次のステップ