ウェブアプリで OpenID Connect を使用して認証する

Identity Platform を使用する Firebase Authentication にアップグレードした場合は、OpenID Connect(OIDC)準拠の任意のプロバイダを使用して Firebase でユーザーを認証できます。これにより、Firebase でネイティブにサポートされていない ID プロバイダを使用できるようになります。

始める前に

OIDC プロバイダを使用してユーザーをログインさせるには、まずプロバイダから次のような情報を収集する必要があります。

  • クライアント ID: アプリを識別するプロバイダに固有の文字列。プロバイダによっては、サポートするプラットフォームごとに異なるクライアント ID を割り当てている場合があります。これは、プロバイダが発行する ID トークン内の aud クレームの値の一つです。

  • クライアント シークレット: プロバイダがクライアント ID の所有権を確認するために使用するシークレット文字列。クライアント ID ごとに、一致するクライアント シークレットが必要です(この値は、認証コードフローを使用する場合にのみ必要です。認証コードフローの使用は強く推奨されています)。

  • 発行元: プロバイダを識別する文字列。この値は、/.well-known/openid-configuration が付加される際に、プロバイダの OIDC ディスカバリ ドキュメントがある URL にする必要があります。たとえば、発行元が https://auth.example.com の場合、ディスカバリ ドキュメントは https://auth.example.com/.well-known/openid-configuration で入手できる必要があります。

上記の情報を取得したら、Firebase プロジェクトのログイン プロバイダとして OpenID Connect を有効にします。

  1. Firebase を JavaScript プロジェクトに追加します

  2. Identity Platform を使用する Firebase Authentication にアップグレードしていない場合は、アップグレードしてください。OpenID Connect 認証は、アップグレードされたプロジェクトでのみ使用できます。

  3. Firebase コンソールの [ログイン プロバイダ] ページで [新しいプロバイダを追加] をクリックし、続いて [OpenID Connect] をクリックします。

  4. 認証コードフローを使用するか、暗黙的な認可フローを使用するかを選択します。

    プロバイダでサポートされているコードフローを常に使用する必要があります。暗黙的フローは安全性が低いため、使用しないことを強くおすすめします。

  5. このプロバイダに名前を付けます。生成されたプロバイダ ID(たとえば、oidc.example-provider など)をメモします。この ID は、ログインコードをアプリに追加するときに必要になります。

  6. クライアント ID とクライアント シークレット、プロバイダの発行元文字列を指定します。これらの値は、プロバイダから割り当てられた値と完全に一致している必要があります。

  7. 変更を保存します。

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

OIDC プロバイダを使用して Firebase でユーザーを認証する最も簡単な方法は、Firebase SDK でログインフロー全体を処理することです。

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

  1. Firebase コンソールで取得したプロバイダ ID を使用して OAuthProvider のインスタンスを作成します。

    ウェブ向けのモジュラー API

    import { OAuthProvider } from "firebase/auth";
    
    const provider = new OAuthProvider('oidc.example-provider');
    

    ウェブ向けの名前空間付き API

    var provider = new firebase.auth.OAuthProvider('oidc.example-provider');
    
  2. 省略可: OAuth リクエストと一緒に送信する追加のカスタム OAuth パラメータを指定します。

    ウェブ向けのモジュラー API

    provider.setCustomParameters({
      // Target specific email with login hint.
      login_hint: 'user@example.com'
    });
    

    ウェブ向けの名前空間付き API

    provider.setCustomParameters({
      // Target specific email with login hint.
      login_hint: 'user@example.com'
    });
    

    サポートされているパラメータについては、プロバイダにお問い合わせください。setCustomParameters で Firebase の必須パラメータを渡すことはできません。該当するパラメータは client_idresponse_typeredirect_uristatescoperesponse_mode です。

  3. 省略可: 認証プロバイダにリクエストする、基本的なプロフィール以外の追加の OAuth 2.0 スコープを指定します。

    ウェブ向けのモジュラー API

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

    ウェブ向けの名前空間付き API

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

    サポートされているスコープについては、プロバイダにお問い合わせください。

  4. OAuth プロバイダ オブジェクトを使用して Firebase での認証を行います。

    ユーザーをプロバイダのログインページにリダイレクトするか、ポップアップ ブラウザ ウィンドウでログインページを開きます。

    リダイレクト フロー

    signInWithRedirect() を呼び出して、プロバイダのログインページにリダイレクトします。

    ウェブ向けのモジュラー API

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

    ウェブ向けの名前空間付き API

    firebase.auth().signInWithRedirect(provider);
    

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

    ウェブ向けのモジュラー API

    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.
      });
    

    ウェブ向けの名前空間付き API

    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.
      });
    

    ポップアップ フロー

    ウェブ向けのモジュラー API

    import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    signInWithPopup(auth, provider)
      .then((result) => {
        // User is signed in.
        // IdP data available using getAdditionalUserInfo(result)
    
        // 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.
      });
    

    ウェブ向けの名前空間付き API

    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.
      });
    
  5. 上記の例ではログインフローを中心に説明していますが、同じパターンで linkWithRedirect()linkWithPopup() を使用して OIDC プロバイダを既存のユーザーにリンクし、reauthenticateWithRedirect()reauthenticateWithPopup() でユーザーを再認証できます。これは、ログインしてから短時間のうちに行うべき機密性の高い操作のために、最新の認証情報を取得するのに使われます。

手動でログインフローを処理する

OpenID Connect ログインフローをアプリにすでに実装している場合は、ID トークンを直接使用して Firebase で認証できます。

ウェブ向けのモジュラー API

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

const provider = new OAuthProvider("oidc.example-provider");
const credential = provider.credential({
    idToken: idToken,
});
signInWithCredential(getAuth(), credential)
    .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.
    });

ウェブ向けの名前空間付き API

const provider = new OAuthProvider("oidc.example-provider");
const credential = provider.credential({
    idToken: idToken,
});
firebase.auth().signInWithCredential(credential)
    .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.
    });