JavaScript で Microsoft を使用した認証を行う

Firebase SDK を使用して汎用の OAuth ログインをアプリに統合し、エンドツーエンドのログインフローを実行することで、ユーザーが Firebase での認証に Microsoft Azure Active Directory などの OAuth プロバイダを使用できます。

始める前に

Microsoft アカウント(Azure Active Directory アカウントや Microsoft の個人アカウント)を使用してユーザーをログインさせるには、まず Firebase プロジェクトのログイン プロバイダとして Microsoft を有効にする必要があります。

  1. Firebase を JavaScript プロジェクトに追加します
  2. Firebase コンソールで [Auth] セクションを開きます。
  3. [Sign-in method] タブで、[Microsoft] プロバイダを有効にします。
  4. そのプロバイダのデベロッパー コンソールで取得したクライアント IDクライアント シークレットをプロバイダ構成に追加します。
    1. クイックスタート: Azure Active Directory v2.0 エンドポイントを使用してアプリを登録するの手順で、Microsoft OAuth クライアントを登録します。 このエンドポイントは、Azure Active Directory アカウントだけでなく、Microsoft の個人アカウントを使用したログインもサポートしています。Azure Active Directory v2.0 に関する詳細をご確認ください。
    2. こうしたプロバイダにアプリを登録するときは、必ずプロジェクトの *.firebaseapp.com ドメインをアプリのリダイレクト ドメインとして登録してください。
  5. [保存] をクリックします。

Firebase SDK を使用したログインフローの処理

ウェブアプリを構築する場合、Microsoft アカウントを使用して Firebase でユーザーを認証する最も簡単な方法は、Firebase JavaScript SDK でログインフロー全体を処理することです。

Firebase JavaScript SDK でログインフローを処理する手順は次のとおりです。

  1. プロバイダ ID OAuthProvider を使用して、OAuthProvider のインスタンスを作成します。

    WebWeb
    import { OAuthProvider } from "firebase/auth";
    
    const provider = new OAuthProvider('microsoft.com');
    var provider = new firebase.auth.OAuthProvider('microsoft.com');
  2. 省略可: OAuth リクエストと一緒に送信する追加のカスタム OAuth パラメータを指定します。

    WebWeb
    provider.setCustomParameters({
      // Force re-consent.
      prompt: 'consent',
      // Target specific email with login hint.
      login_hint: 'user@firstadd.onmicrosoft.com'
    });
    provider.setCustomParameters({
      // Force re-consent.
      prompt: 'consent',
      // Target specific email with login hint.
      login_hint: 'user@firstadd.onmicrosoft.com'
    });

    Microsoft がサポートするパラメータについては、Microsoft の OAuth に関するドキュメントをご覧ください。setCustomParameters() で Firebase の必須パラメータを渡すことはできません。該当するパラメータは、client_idresponse_typeredirect_uristatescoperesponse_mode です。

    Azure AD テナントのわかりやすいドメイン名またはテナントの GUID 識別子を使用して、特定の Azure AD テナントのユーザーのみがアプリケーションにログインするようにできます。これは、カスタム パラメータ オブジェクトの「tenant」フィールドを指定することによって実行できます。

    WebWeb
    provider.setCustomParameters({
      // Optional "tenant" parameter in case you are using an Azure AD tenant.
      // eg. '8eaef023-2b34-4da1-9baa-8bc8c9d6a490' or 'contoso.onmicrosoft.com'
      // or "common" for tenant-independent tokens.
      // The default value is "common".
      tenant: 'TENANT_ID'
    });
    provider.setCustomParameters({
      // Optional "tenant" parameter in case you are using an Azure AD tenant.
      // eg. '8eaef023-2b34-4da1-9baa-8bc8c9d6a490' or 'contoso.onmicrosoft.com'
      // or "common" for tenant-independent tokens.
      // The default value is "common".
      tenant: 'TENANT_ID'
    });
  3. 省略可: 認証プロバイダにリクエストする、基本的なプロフィール以外の追加の OAuth 2.0 スコープを指定します。

    provider.addScope('mail.read');
    provider.addScope('calendars.read');

    詳しくは、Microsoft のアクセス許可と同意に関するドキュメントをご覧ください。

  4. OAuth プロバイダ オブジェクトを使用して Firebase での認証を行います。ユーザーに Microsoft アカウントでログインするよう促すために、ポップアップ ウィンドウを表示するか、ログインページにリダイレクトします。モバイル デバイスではリダイレクトすることをおすすめします。

    • ポップアップ ウィンドウでログインを行う場合は、signInWithPopup を呼び出します。
    WebWeb
    import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    signInWithPopup(auth, provider)
      .then((result) => {
        // User is signed in.
        // IdP data available in result.additionalUserInfo.profile.
    
        // Get the OAuth access token and ID Token
        const credential = OAuthProvider.credentialFromResult(result);
        const accessToken = credential.accessToken;
        const idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });
    firebase.auth().signInWithPopup(provider)
      .then((result) => {
        // IdP data available in result.additionalUserInfo.profile.
        // ...
    
        /** @type {firebase.auth.OAuthCredential} */
        var credential = result.credential;
    
        // OAuth access and id tokens can also be retrieved:
        var accessToken = credential.accessToken;
        var idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });
    • ログインページにリダイレクトしてログインを行う場合は、signInWithRedirect を呼び出します。

    signInWithRedirectlinkWithRedirectreauthenticateWithRedirect を使用する場合は、ベスト プラクティスに従ってください。

    WebWeb
    import { getAuth, signInWithRedirect } from "firebase/auth";
    
    const auth = getAuth();
    signInWithRedirect(auth, provider);
    firebase.auth().signInWithRedirect(provider);

    ユーザーがログインを完了してページに戻ったら、getRedirectResult を呼び出してログイン結果を取得できます。

    WebWeb
    import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    getRedirectResult(auth)
      .then((result) => {
        // User is signed in.
        // IdP data available in result.additionalUserInfo.profile.
    
        // Get the OAuth access token and ID Token
        const credential = OAuthProvider.credentialFromResult(result);
        const accessToken = credential.accessToken;
        const idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });
    firebase.auth().getRedirectResult()
      .then((result) => {
        // IdP data available in result.additionalUserInfo.profile.
        // ...
    
        /** @type {firebase.auth.OAuthCredential} */
        var credential = result.credential;
    
        // OAuth access and id tokens can also be retrieved:
        var accessToken = credential.accessToken;
        var idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });

    正常に完了すると、プロバイダに関連付けられている OAuth アクセス トークンを、返された firebase.auth.UserCredential オブジェクトから取得できます。

    OAuth アクセス トークンを使用して、Microsoft Graph API を呼び出せます。

    たとえば、基本的なプロフィール情報を取得するには、次の REST API を呼び出します。

    curl -i -H "Authorization: Bearer ACCESS_TOKEN" https://graph.microsoft.com/v1.0/me

    Firebase Auth でサポートされている他のプロバイダとは異なり、Microsoft では写真の URL が提供されないため、代わりにプロフィール写真のバイナリデータを Microsoft Graph API を介してリクエストする必要があります。

    OAuth アクセス トークンに加えて、ユーザーの OAuth ID トークンfirebase.auth.UserCredential オブジェクトから取得できます。ID トークン内の sub クレームはアプリ固有のものであり、Firebase Auth で使用される連携ユーザー識別子(user.providerData[0].uid を通じてアクセス可能)とは一致しません。代わりに oid クレーム フィールドを使用する必要があります。Azure AD テナントを使用してログインする場合は、oid クレームと完全に一致します。ただし、テナント以外のケースについては、oid フィールドはパディングされます。フェデレーション ID が 4b2eabcdefghijkl の場合、oid の形式は 00000000-0000-0000-4b2e-abcdefghijkl のようになります。

  5. 上述の例ではログインフローを中心に説明していますが、linkWithPopup / linkWithRedirect を使用して Microsoft プロバイダを既存のユーザーにリンクすることもできます。たとえば、複数のプロバイダを同じユーザーにリンクして、どれでもログインすることができます。

    WebWeb
    import { getAuth, linkWithPopup, OAuthProvider } from "firebase/auth";
    
    const provider = new OAuthProvider('microsoft.com');
    const auth = getAuth();
    
    linkWithPopup(auth.currentUser, provider)
        .then((result) => {
          // Microsoft credential is linked to the current user.
          // IdP data available in result.additionalUserInfo.profile.
    
          // Get the OAuth access token and ID Token
          const credential = OAuthProvider.credentialFromResult(result);
          const accessToken = credential.accessToken;
          const idToken = credential.idToken;
        })
        .catch((error) => {
          // Handle error.
        });
    var provider = new firebase.auth.OAuthProvider('microsoft.com');
    firebase.auth().currentUser.linkWithPopup(provider)
        .then((result) => {
          // Microsoft credential is linked to the current user.
          // IdP data available in result.additionalUserInfo.profile.
          // OAuth access token can also be retrieved:
          // result.credential.accessToken
          // OAuth ID token can also be retrieved:
          // result.credential.idToken
        })
        .catch((error) => {
          // Handle error.
        });
  6. 同じパターンを reauthenticateWithPopup / reauthenticateWithRedirect でも使用できます。これは、ログインしてから短時間のうちに行うべき機密性の高い操作のために、最新の認証情報を取得するのに使われます。

    WebWeb
    import { getAuth, reauthenticateWithPopup, OAuthProvider } from "firebase/auth";
    
    const provider = new OAuthProvider('microsoft.com');
    const auth = getAuth();
    reauthenticateWithPopup(auth.currentUser, provider)
        .then((result) => {
          // User is re-authenticated with fresh tokens minted and
          // should be able to perform sensitive operations like account
          // deletion and email or password update.
          // IdP data available in result.additionalUserInfo.profile.
    
          // Get the OAuth access token and ID Token
          const credential = OAuthProvider.credentialFromResult(result);
          const accessToken = credential.accessToken;
          const idToken = credential.idToken;
        })
        .catch((error) => {
          // Handle error.
        });
    var provider = new firebase.auth.OAuthProvider('microsoft.com');
    firebase.auth().currentUser.reauthenticateWithPopup(provider)
        .then((result) => {
          // User is re-authenticated with fresh tokens minted and
          // should be able to perform sensitive operations like account
          // deletion and email or password update.
          // IdP data available in result.additionalUserInfo.profile.
          // OAuth access token can also be retrieved:
          // result.credential.accessToken
          // OAuth ID token can also be retrieved:
          // result.credential.idToken
        })
        .catch((error) => {
          // Handle error.
        });

Firebase コンソールで [1 つのメールアドレスにつき 1 つのアカウント] 設定を有効にしている場合、Firebase ユーザーが、あるプロバイダ(Google など)用にすでに存在しているメールアドレスを使って別のプロバイダ(Microsoft など)にログインしようとすると、AuthCredential オブジェクト(Microsoft の認証情報)とともにエラー auth/account-exists-with-different-credential がスローされます。目的のプロバイダにログインするには、まず既存のプロバイダ(Google)にログインしてから、目的のプロバイダの AuthCredential(Microsoft の認証情報)にリンクする必要があります。

signInWithPopup を使用する場合、次のようなコードによって auth/account-exists-with-different-credential エラーを処理できます。

import {
  getAuth,
  linkWithCredential,
  signInWithPopup,
  OAuthProvider,
} from "firebase/auth";

try {
  // Step 1: User tries to sign in using Microsoft.
  let result = await signInWithPopup(getAuth(), new OAuthProvider());
} catch (error) {
  // Step 2: User's email already exists.
  if (error.code === "auth/account-exists-with-different-credential") {
    // The pending Microsoft credential.
    let pendingCred = error.credential;

    // Step 3: Save the pending credential in temporary storage,

    // Step 4: Let the user know that they already have an account
    // but with a different provider, and let them choose another
    // sign-in method.
  }
}

// ...

try {
  // Step 5: Sign the user in using their chosen method.
  let result = await signInWithPopup(getAuth(), userSelectedProvider);

  // Step 6: Link to the Microsoft credential.
  // TODO: implement `retrievePendingCred` for your app.
  let pendingCred = retrievePendingCred();

  if (pendingCred !== null) {
    // As you have access to the pending credential, you can directly call the
    // link method.
    let user = await linkWithCredential(result.user, pendingCred);
  }

  // Step 7: Continue to app.
} catch (error) {
  // ...
}

リダイレクト モード

このエラーはリダイレクト モードでも同様の方法で処理されますが、ページをリダイレクトする間、保留された認証情報をキャッシュに保存する必要がある点が異なります(セッション ストレージなどを使用します)。

OAuth アクセス トークンに基づいた認証情報を使用して直接ログインできる、Firebase でサポートされている他の OAuth プロバイダ(Google、Facebook、Twitter など)と違い、Microsoft などのプロバイダでは Firebase Auth で同様の機能がサポートされていません。これは Firebase Auth サーバーが Microsoft OAuth アクセス トークンの対象デバイスを検証できないからです。これは重要なセキュリティ要件です。検証が行われないと、攻撃者があるプロジェクト用に取得した Microsoft OAuth アクセス トークンを使用して別のプロジェクト(被害者)にログインすることが可能となり、アプリケーションやウェブサイトはリプレイ攻撃にさらされる恐れがあります。代わりに Firebase Auth では、Firebase コンソールで構成した OAuth のクライアント ID とクライアント シークレットを使用して、OAuth フロー全体と認証コード交換を処理する機能を提供しています。認証コードは特定のクライアント ID / シークレットの組み合わせでのみ使用できるため、あるプロジェクトで取得した認証コードを別のプロジェクトで使用することはできません。

このようなプロバイダを、サポートされていない環境で使用する必要がある場合は、サードパーティの OAuth ライブラリと Firebase カスタム認証を使用する必要があります。前者はプロバイダとの認証に、後者はプロバイダの認証情報をカスタム トークンと交換するために必要です。

Chrome 拡張機能で Firebase による認証を行う

Chrome 拡張機能アプリを作成する場合は、画面外ドキュメントのガイドをご覧ください。

プロジェクトの作成時に、Firebase は次のようなプロジェクト固有のサブドメインをプロビジョニングします。 https://my-app-12345.firebaseapp.com

これは、OAuth ログインのリダイレクト メカニズムとしても使用されます。このドメインは、サポートされているすべての OAuth プロバイダに許可される必要があります。この場合、ユーザーが Microsoft にログインしている間、アプリケーションにリダイレクトする前に [Continue to: https://my-app-12345.firebaseapp.com] のようにドメインを含むメッセージが表示される可能性があります。

サブドメインが表示されないようにするには、Firebase Hosting でカスタム ドメインを設定します。

  1. Hosting 用にドメインを設定するの手順 1~3 を行います。ドメインの所有権を確認すると、Hosting はカスタム ドメイン向けに SSL 証明書をプロビジョニングします。
  2. Firebase コンソールで、認可済みドメインのリストにカスタム ドメイン auth.custom.domain.com を追加します。
  3. Microsoft のデベロッパー コンソールまたは OAuth 設定ページで、リダイレクト ページの URL(https://auth.custom.domain.com/__/auth/handler)を許可リストに登録します。これにより、カスタム ドメインでアクセス可能になります。
  4. JavaScript ライブラリを初期化するときに、authDomain フィールドにカスタム ドメインを指定します。
    var config = {
      apiKey: '...',
      // Changed from 'PROJECT_ID.firebaseapp.com'.
      authDomain: 'auth.custom.domain.com',
      databaseURL: 'https://PROJECT_ID.firebaseio.com',
      projectId: 'PROJECT_ID',
      storageBucket: 'PROJECT_ID.firebasestorage.app',
      messagingSenderId: 'SENDER_ID'
    };
    firebase.initializeApp(config);

次のステップ

ユーザーが初めてログインすると、新しいユーザー アカウントが作成され、ユーザーがログイン時に使用した認証情報(ユーザー名とパスワード、電話番号、または認証プロバイダ情報)にアカウントがリンクされます。この新しいアカウントは Firebase プロジェクトの一部として保存され、ユーザーのログイン方法にかかわらず、プロジェクトのすべてのアプリでユーザーを識別するために使用できます。

  • アプリでユーザーの認証ステータスを把握するには、Auth オブジェクトにオブザーバーを設定することをおすすめします。これによって、ユーザーの基本的なプロフィール情報を User オブジェクトから取得できます。ユーザーを管理するをご覧ください。

  • Firebase Realtime DatabaseCloud Storageセキュリティ ルールでは、ログイン済みユーザーの一意のユーザー ID を auth 変数から取得し、それを使用して、ユーザーがアクセスできるデータを制御できます。

既存のユーザー アカウントに認証プロバイダの認証情報をリンクすることで、ユーザーは複数の認証プロバイダを使用してアプリにログインできるようになります。

ユーザーのログアウトを行うには、signOut を呼び出します。

WebWeb
import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});
firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});