Identity Platform を使用する Firebase Authentication にアップグレードした場合は、アプリに時間ベースのワンタイム パスワード(TOTP)多要素認証(MFA)を追加できます。
Identity Platform を使用する Firebase Authentication では、MFAの追加要素として TOTP を使用できます。この機能を有効にした後、ユーザーがアプリにログインしようとすると、TOTP のリクエストが表示されます。有効な TOTP コードを生成するには、Google 認証システムなど、それを生成できる認証システムアプリを使用する必要があります。
準備
MFA をサポートするプロバイダを少なくとも 1 つ有効にします。以下を除くすべてのプロバイダが MFA をサポートしています。
- 電話認証
- 匿名認証
- カスタム認証トークン
- Apple Game Center
アプリでユーザーのメールアドレスが検証されるようにします。MFA では、メールの確認を行う必要があります。これにより、悪意のある人物が所有していないメールアドレスでサービスに登録してから第 2 要素を追加することで、そのメールアドレスの実際の所有者をロックアウトすることを防ぎます。
Firebase JavaScript SDK をまだインストールしていない場合は、インストールします。
TOTP MFA は、バージョン v9.19.1 以降のモジュラー Web SDK でのみサポートされます。
Firebase Admin SDK をまだインストールしていない場合は、インストールします。
TOTP MFA は、Firebase Admin SDK バージョン 11.6.0 以降でのみサポートされています。
TOTP MFA を有効にする
第 2 要素として TOTP を有効にするには、Admin SDK を使用するか、プロジェクト構成 REST エンドポイントを呼び出します。
Admin SDK を使用するには、次のコマンドを実行します。
import { getAuth } from 'firebase-admin/auth';
getAuth().projectConfigManager().updateProjectConfig(
{
multiFactorConfig: {
providerConfigs: [{
state: "ENABLED",
totpProviderConfig: {
adjacentIntervals: {
NUM_ADJ_INTERVALS
},
}
}]
}
})
以下を置き換えます。
NUM_ADJ_INTERVALS
: 時間枠間隔の数(0 ~ 10) デフォルトは 5 です。
REST API を使用して TOTP MFA を有効にするには、次のコマンドを実行します。
curl -X PATCH "https://identitytoolkit.googleapis.com/admin/v2/projects/PROJECT_ID/config?updateMask=mfa" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-H "X-Goog-User-Project: PROJECT_ID" \
-d \
'{
"mfa": {
"providerConfigs": [{
"state": "ENABLED",
"totpProviderConfig": {
"adjacentIntervals": "NUM_ADJ_INTERVALS"
}
}]
}
}'
以下を置き換えます。
PROJECT_ID
: プロジェクト ID。NUM_ADJ_INTERVALS
: 時間枠間隔の数(0 ~ 10) デフォルトは 5 です。
登録パターンを選択する
アプリで多要素認証が必要かどうかと、ユーザーを登録する方法とタイミングを選択できます。一般的なパターンには、次のようなものがあります。
登録の一部として、ユーザーの第 2 要素を登録する。アプリがすべてのユーザーに対して多要素認証を必要とする場合は、この方法を使用します。
登録中に第 2 要素の登録をスキップできる選択肢を用意する。アプリで多要素認証を必須とはしないが、推奨したい場合は、この方法を使用できます。
登録画面ではなく、ユーザーのアカウントまたはプロフィールの管理ページから第 2 要素を追加する機能を用意する。これにより、登録プロセス中の摩擦が最小限に抑えられる一方、セキュリティに敏感なユーザーは多要素認証を利用できるようになります。
セキュリティ要件が強化された機能にユーザーがアクセスする際には、第 2 要素を段階的に追加することを要求する。
TOTP MFA にユーザーを登録する
アプリの第 2 要素として TOTP MFA を有効にしたら、TOTP MFA にユーザーを登録するクライアント側ロジックを実装します。
必要な MFA クラスと関数をインポートします。
import { multiFactor, TotpMultiFactorGenerator, TotpSecret, getAuth, } from "firebase/auth";
ユーザーを再認証します。
認証されたユーザーの TOTP シークレットを生成します。
// Generate a TOTP secret. const multiFactorSession = await multiFactor(currentUser).getSession(); const totpSecret = await TotpMultiFactorGenerator.generateSecret( multiFactorSession );
ユーザーにシークレットを表示し、認証アプリに入力するようユーザーに求めます。
多くの認証システムアプリでは、Google 認証システムと互換性のあるキー URI を表す QR コードをスキャンすることで、新しい TOTP シークレットをすばやく追加できます。この目的の QR コードを生成するには、
generateQrCodeUrl()
で URI を生成し、任意の QR コード ライブラリを使用してエンコードします。次に例を示します。const totpUri = totpSecret.generateQrCodeUrl( currentUser.email, "Your App's Name" ); await QRExampleLib.toCanvas(totpUri, qrElement);
QR コードを表示するかどうかに関係なく、QR コードを読み取ることができない認証システムアプリをサポートするために、常にシークレットキーを表示します。
// Also display this key: const secret = totpSecret.secretKey;
ユーザーが認証システム アプリにシークレットを追加すると、TOTP の生成が開始されます。
認証システム アプリに表示された TOTP を入力し、それを使用して MFA 登録を確定するようユーザーに促します。
// Ask the user for a verification code from the authenticator app. const verificationCode = // Code from user input. // Finalize the enrollment. const multiFactorAssertion = TotpMultiFactorGenerator.assertionForEnrollment( totpSecret, verificationCode ); await multiFactor(currentUser).enroll(multiFactorAssertion, mfaDisplayName);
第 2 要素でのユーザーのログイン
TOTP MFA でユーザーをログインさせるには、次のコードを使用します。
必要な MFA クラスと関数をインポートします。
import { getAuth, getMultiFactorResolver, TotpMultiFactorGenerator, } from "firebase/auth";
MFA を使用していない場合と同様に、
signInWith
メソッドのいずれかを呼び出します。(例:signInWithEmailAndPassword()
)。このメソッドからauth/multi-factor-auth-required
エラーがスローされた場合は、アプリの MFA フローを開始します。try { const userCredential = await signInWithEmailAndPassword( getAuth(), email, password ); // If the user is not enrolled with a second factor and provided valid // credentials, sign-in succeeds. // (If your app requires MFA, this could be considered an error // condition, which you would resolve by forcing the user to enroll a // second factor.) // ... } catch (error) { switch (error.code) { case "auth/multi-factor-auth-required": // Initiate your second factor sign-in flow. (See next step.) // ... break; case ...: // Handle other errors, such as wrong passwords. break; } }
アプリの MFA フローでは、まず、使用する第 2 要素を選択するようユーザーに促します。サポートされている第 2 要素のリストを取得するには、
MultiFactorResolver
インスタンスのhints
プロパティを調べます。const mfaResolver = getMultiFactorResolver(getAuth(), error); const enrolledFactors = mfaResolver.hints.map(info => info.displayName);
ユーザーが TOTP の使用を選択した場合は、認証システム アプリに表示された TOTP を入力し、それを使用してログインするようにユーザーに求めます。
switch (mfaResolver.hints[selectedIndex].factorId) { case TotpMultiFactorGenerator.FACTOR_ID: const otpFromAuthenticator = // OTP typed by the user. const multiFactorAssertion = TotpMultiFactorGenerator.assertionForSignIn( mfaResolver.hints[selectedIndex].uid, otpFromAuthenticator ); try { const userCredential = await mfaResolver.resolveSignIn( multiFactorAssertion ); // Successfully signed in! } catch (error) { // Invalid or expired OTP. } break; case PhoneMultiFactorGenerator.FACTOR_ID: // Handle SMS second factor. break; default: // Unsupported second factor? break; }
TOTP MFA の登録を解除する
このセクションでは、ユーザーによる TOTP MFA の登録の解除を処理する方法について説明します。
ユーザーが複数の MFA オプションに登録し、最後に有効にしたオプションから登録を解除した場合は、ユーザーはauth/user-token-expired
を受け取ってログアウトされます。ユーザーはもう一度ログインして、既存の認証情報(メールアドレスとパスワードなど)を確認する必要があります。
ユーザーの登録を解除してエラーを処理し、再認証をトリガーするには、次のコードを使用します。
import {
EmailAuthProvider,
TotpMultiFactorGenerator,
getAuth,
multiFactor,
reauthenticateWithCredential,
} from "firebase/auth";
try {
// Unenroll from TOTP MFA.
await multiFactor(currentUser).unenroll(TotpMultiFactorGenerator.FACTOR_ID);
} catch (error) {
if (error.code === 'auth/user-token-expired') {
// If the user was signed out, re-authenticate them.
// For example, if they signed in with a password, prompt them to
// provide it again, then call `reauthenticateWithCredential()` as shown
// below.
const credential = EmailAuthProvider.credential(email, password);
await reauthenticateWithCredential(
currentUser,
credential
);
}
}
次のステップ
- Admin SDK を使用して、プログラムで多要素ユーザーを管理する。