Docker上で動かしたFirebase Authのエミュレータにローカル環境のフロントエンドとバックエンド(Cloudflare + Hono)から接続したメモ

# 概要
[前回は、Firebase Authを使ったログイン](https://qiita.com/hibohiboo/items/6c8e309bec9a6cda1a49)を行った。
今回は、ローカルでFirebase Authのエミュレータを使った開発ができる環境を整える。

[ソースコード](https://github.com/hibohiboo/odyssage/blob/3f1479c4e2672a1e116ee310748bd0688afafa37/infla/local/firebase/docker-compose.yml)

# ローカル環境
- Windows 11 Home 24H2 26100.2605
- Docker version 27.3.1, build ce12230
- Node v22.11.0
- bun 1.1.42
- ⛅️ wrangler 3.99.0
# Cloudflare Workersのローカル実行
[Local Develop](https://developers.cloudflare.com/workers/testing/local-development/)の[wrangler dev](https://developers.cloudflare.com/workers/wrangler/commands/#dev)で実行。
[Get Started](https://developers.cloudflare.com/workers/get-started/guide/)で作成されるフォーマットの通りにやれば動作した。

# Google Firebase Authentication のローカル実行

[公式エミュレータ](https://firebase.google.com/docs/emulator-suite/connect_auth?hl=ja&_gl=1*1c9ilao*_up*MQ..*_ga*MTE3ODM4ODcwNC4xNzM1OTk0MjUz*_ga_CW55HF8NVT*MTczNTk5NDI1My4xLjAuMTczNTk5NDI1My4wLjAuMA..)がある。
[Dockerのコンテナ内でFirebase Emulatorを動かしたい](https://zenn.dev/roll1226/articles/d1ebcc58558380)と[Firebase Local Emulator SuiteをDocker環境で構築して、アプリケーションからテストを実行してみた](https://qiita.com/ppco/items/87682b3a14ceb3702dbb)を参考にDockerでエミュレータを動かした。
バックエンドは[Cloudflare Workers でも Firebase Authentication を使えるぞ！！](https://zenn.dev/codehex/articles/ca85a1babcc046)を参考に設定。

```docker:infra/local/firebase/docker/Dockerfile
FROM ubuntu:22.04

RUN apt update && \
apt install -y curl openjdk-17-jdk && \
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
apt install -y nodejs

RUN npm install -g firebase-tools
```


```yml:infra/local/firebase/docker-compose.yml
version: '3.9'

services:
  firebase:
    build:
      context: .
      dockerfile: ./docker/Dockerfile
    volumes:
       # 初期設定が終わったら削除
       - ./tmp:/opt/tmp
# 初期設定が終わったらコメントアウト解除
#      - ./firebase.json:/opt/firebase/firebase.json
#      - ./.firebaserc:/opt/firebase/.firebaserc
#      - ./config:/root/.config:cached
#      - ./cache:/root/.cache:cached

    ports:
      - 9099:9099 # Firebase Authentication
      - 9005:9005 # Firebase login
      - 4000:4000 # Firebase UI
    working_dir: /opt/firebase
    command: firebase emulators:start
    tty: true
```

`docker-compose build`でコンテナを作成し、`docker-compose run --service-ports firebase bash`でコンテナ内に入り初期設定を行う。

まずは、`cd /opt/tmp` `firebase login`でログインする。表示されるリンクを踏むとブラウザで下記のような画面が出るのでFirebase Cliにアクセスの許可を与える。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/015da6bb-5070-3865-dce4-cd86868cd052.png)

最後に下記のような画面がブラウザに表示されたらログイン成功。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/a1475307-535d-6f35-48ed-a953ab220e81.png)

つぎに`firebase init`で初期設定を行う。
今回はエミュレータ用の設定を行いたいので、エミュレータを選んでスペースキーを押下して選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/04fb1419-1873-76b1-1fa1-5f8c6f25b5f6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/dbb367c2-d7a5-2e40-1cdd-52913d1390e0.png)
プロジェクトを選んだり、いろいろ回答していく。途中の画像は割愛。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/ec70d251-2d1e-95c7-614a-292337b4dbcc.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/b456aa58-2a7a-4bf8-64d0-2847c2cdcff3.png)

最終的に、`.firebaserc`,`firebase.json`,`.gitignore`の３つのファイルが作成される。このうち`.firebaserc`と`firebase.json`を使う。いったんDockerは切断し、`docker-compose.yml`のvolumesを修正する。

```json:infra/local/firebase/.firebaserc
{
  "projects": {
    "default": "hogehoge"
  }
}
```

Docker内のポートにアクセスできるよう、作成された`firebase.json`ファイルに少し手を加える。

```diff:infra/local/firebase/firebase.json
{
  "emulators": {
    "auth": {
      "port": 9099,
+      "host": "0.0.0.0"
    },
    "ui": {
      "enabled": true,
      "port": 4000,
+      "host": "0.0.0.0"
    },
    "singleProjectMode": true
  }
}
```

これで`docker-compose up`を行うと下記のようにエミュレータが立ち上がることが確認できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/d581a867-765c-b067-62a9-bdc7c6f63417.png)

`http://127.0.0.1:4000`にアクセスするとエミュレータのUIが確認できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/9ec87e03-9b80-2157-f4fa-c67754c34ddc.png)

## フロントエンドの修正

```diff:apps/frontend/src/shared/lib/auth/firebaseAuth.ts
import {
+ connectAuthEmulator,
  getAuth,
  NextOrObserver,
  onAuthStateChanged,
  signInAnonymously,
  User,
} from 'firebase/auth';
import { initializeApp } from 'firebase/app';

const firebaseConfig = {
  apiKey: import.meta.env.VITE_FIREBASE_API_KEY as string,
  authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN as string,
  projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID as string,
};
const firebaseApp = initializeApp(firebaseConfig);
const auth = getAuth(firebaseApp);

+ if (import.meta.env.DEV) {
+   connectAuthEmulator(auth, 'http://127.0.0.1:9099');
+ }

export const signInAnonymous = async () => {
  const ret = await signInAnonymously(auth);
  console.log('signInAnonymous', ret);
  return ret;
};
export const onAuthStateChangedListener = (callback: NextOrObserver<User>) =>
  onAuthStateChanged(auth, callback);
export const getIdToken = async () => {
  const user = auth.currentUser;
  if (user == null) {
    return null;
  }
  return user.getIdToken();
};
```

## バックエンドの修正

```diff:apps/backend/.dev.vars
NEON_CONNECTION_STRING=postgresql://<DB_USER_NAME>:<DB_PASSWORD>@<NEON_DB_DOMAIN>.us-west-2.aws.neon.tech/main?sslmode=require
NEO4J_URL=neo4j+s://<NEO4J_INSTANCE_DOMAIN>.databases.neo4j.io
NEO4J_USER=neo4j
NEO4J_PASSWORD=<NEO4J_PASSWORD>

FIREBASE_PROJECT_ID=hogehoge
+ FIREBASE_AUTH_EMULATOR_HOST=127.0.0.1:9099
```



# 参考
[API Gateway + Lambda+Hasuraの構成をローカルで模倣してテストを行ったメモ](https://qiita.com/hibohiboo/items/16595aaa9cd78dc1a9c2)
[AWS CDKで作成したAPIGateway+Lambda(Node18)をローカルで動かしてみたメモ](https://qiita.com/hibohiboo/items/45a673ca70d42f3d1f4b)