👌

Next.js で AppCheck(Firebase) を使う

2022/07/04に公開

Next.js(Vercel) & Firebase で作成したサービスに AppCheck を組み込んだ手順をまとめました。AppCheck はバックエンドとして信頼できる所以外のアクセスを制限しようというものです。
https://firebase.google.com/docs/app-check

前提条件

Next.js でサービスを作成し、Vercel にデプロイして運用しています。
バックエンドに Firebase を利用しています。

reCHAPTA キー取得

まず、認証につかうキーを取得します。

https://www.google.com/recaptcha/about/

  1. 「v3 Admin Console」 を選択
  2. 「+(作成)」 を選択
  3. 項目の入力
項目 内容(例) 備考
ラベル tekito.vercel.app 識別のできる名前
reCAPTCHA タイプ reCAPTCHA v3
ドメイン tekito.vercel.app 独自ドメインがあれば追加
オーナー (自分のgoogleアカウント) 既定値
reCAPTCHA 利用条件に同意する チェック
アラートをオーナーに送信する チェック
  1. 入力が終わったら 「送信」 をクリックします。生成された2つのキーのうち サイトキー はNext.jsに実装し、シークレットキーはFirebaseに登録して使用します。

AppCheck(Firebase) 登録

  1. Firebase コンソールにログインします。

  2. Firebae の対象プロジェクト内のプロジェクトショートカットから AppCheck を起動します。

  3. 初回であれば 「始める」 をクリックします。

  4. ステータスの下にある 「登録」 をクリックします。

  5. 今回は reCAPTCHA v3 を使うので 「reCHAPTCHA」 を選択します。

  6. 「reCAPTCHA 秘密鍵」 の欄に、先ほど取得した 「シークレットキー」 を入力(貼付)します。トークンの有効期間はそのまま既定値とします。入力できたら 「保存」 をクリックします。

Next.js 側の実装

Firebase の初期化処理の後に AppCheck の初期化処理を入れます。
私の場合は _app.tsx の中に firebase.ts をインポートしているので以下の感じで実装しました。

https://zenn.dev/dala/books/nextjs-firebase-service

  1. _app.tsx にインポートしておいて
/src/pages/_app.tsx
import '../lib/firebase'
(以下省略)
  1. 以下の感じで作成しました。
/src/lib/firebase.ts
import { getApp, getApps, initializeApp } from 'firebase/app'
import { initializeAppCheck, ReCaptchaV3Provider, getToken } from 'firebase/app-check'

// 環境変数から FirebaseConfig の読み込みをしています
const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
  measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
}

// Firebase 初期化処理
export const firebase = getApps().length === 0 ? initializeApp(firebaseConfig) : getApp()

// FIREBASE_APPCHECK_DEBUG_TOKEN の定義(TypeScript用)
declare global {
  var FIREBASE_APPCHECK_DEBUG_TOKEN: boolean | string | undefined
}

// AppCheck 初期化処理
if (typeof document !== 'undefined') {
  // 1.デバック環境用設定
  if (process.env.NODE_ENV === 'development') {
    window.self.FIREBASE_APPCHECK_DEBUG_TOKEN = true // デバッグ用文字列の生成
  }
  // 2.AppCheck 初期化
  const appCheck = initializeAppCheck(firebase, {
    provider: new ReCaptchaV3Provider('ここにreCHAPTAサイトキーを貼り付け'),
    isTokenAutoRefreshEnabled: true,
  })
  // 3.AppCheck 結果 & トークン確認
  getToken(appCheck)
    .then(() => {
      console.log('AppCheck:Success')
    })
    .catch((error) => {
      console.log(error.message)
    })
}
  1. AppCheck 初期化の部分に取得した 「サイトキー」 の方を貼り付け、「保存」 をクリックします。

開発環境用トークンの登録

開発環境からのアクセスは localhost からのアクセスとなり、このままでは 「未確認のリクエスト」 になってしまうので、トークンを登録してエラーが出ないようにします。

  1. Next.js を デバックモードで起動します。
    Chrome の Console にトークンが出力されます。(トークンの部分を削除しています)

  2. トークンの文字列をコピーし、Firebase の AppCheck を再度開きます。
    タブが 「アプリ」 の方になっていれば、先ほど reCAPTCHA を登録した画面になります。証明書右側の縦3点の部分(メニューを開く)をクリックして、 「デバッグトークンを管理」 をクリックします。

  3. 「デバッグトークン」 をクリックし、デバックトークンを登録します。名前は適当な文字列、値は先ほど Next.js のログに表示された文字列を貼り付けます。入力したら 「完了」 をクリックします。

  4. 完了です。これで開発環境(localhost)からFirebaseにアクセスしてもエラーが表示されなくなります。成功時にログに 「AppCheck:Success」 が表示されているか確認できます。(トークン取得時にログが表示されるようにしています。)

状況の確認

  1. デバッグで動作確認をし、問題なければデプロイ(Vercel)します。
  2. 公開しているURLからFirebaseへのアクセスが正常にできているか確認します。
  3. しばらくすると、AppCheck(Firebase)側に検証結果が表示されていきます。

  1. サービスを運用中であればアナウンスなどを行い確認済みのリクエストが増えていくのを確認し、良いと判断したところで 「適用」 をクリックすることで、確認済みのリクエストの場合のみアクセス可能にできます。

参考

https://firebase.google.com/docs/app-check/web/recaptcha-provider#web-version-9

https://firebase.google.com/docs/app-check/web/debug-provider#web-version-9

https://stackoverflow.com/questions/71612148/typescript-error-property-firebase-appcheck-debug-token-does-not-exist-on-typ

https://zenn.dev/ebiyy/scraps/2e1983082b1bf5

Discussion