Firebase + Microsoft で認証機能実装

# 背景
自社サービス作成時に社内で使用しているMicrosoft365アカウントで認証出来るようにするという仕様になりました
`Firebase`と`Microsoft Entral ID`を使用しての認証機能実装が可能ということは知っていたのですが

* 実装方法がわからなかった
* 調べても殆ど記事が見つからなかった

というのもあり記事に残して今後似た実装する可能性のあるエンジニアのために記事にの構想と思った次第です

https://www.microsoft.com/ja-jp/security/business/identity-access/microsoft-entra-id

https://firebase.google.com/docs/auth/web/microsoft-oauth?hl=ja

https://qiita.com/kawashinji/items/1ba25ef6cc5c1532ee09

https://dev.to/425show/integrate-azure-ad-with-firebase-and-call-ms-graph-in-a-node-js-app-973

# ファイル構成
```zsh
.
└── src
    ├── App.css
    ├── App.ts
    ├── configs
    │   └── firebase.ts → Firebaseの初期化用
    ├── hooks
    │   └── useAuth.ts → 認証周りの処理
    ├── index.css
    ├── main.tsx
    └── vite-env.d.ts
```

# プロジェクト作成

```zsh:zsh
npm create vite@latest
```

上記コマンドをターミナルで叩いて対話形式で会話していきます

1. Project name
    * 自分自身の分かりやすい名前にしてください
1. Select a framework
    * Reactを選択(別フレームワークでも問題ありませんが、今後書いていくコードは読み替えてください)
1. Select a variant
    * Typescriptを選択(TypescriptではなくJavascriptでも問題ありませんが、今後書いていくコードは読み替えてください)

```zsh:zsh
npm create vite@latest
│
◇  Project name:
│  vite-project
│
◇  Select a framework:
│  React
│
◇  Select a variant:
│  TypeScript
│
◇  Scaffolding project in /Users/roll1226/personalDevelopment/vite-project...
│
└  Done. Now run:

  cd vite-project
  npm install
  npm run dev
```

![CleanShot 2025-02-26 at 07.18.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/e43b3422-a645-47fe-a5e5-528992f5bc7a.png)

## コードを書いていく

### vite-env.d.ts
環境変数の型を定義していきます

```diff_typescript:vite-env.d.ts
/// <reference types="vite/client" />

+ interface ImportMetaEnv {
+   VITE_API_KEY: string;
+   VITE_AUTH_DOMAIN: string;
+   VITE_PROJECT_ID: string;
+   VITE_STORAGE_BUCKET: string;
+   VITE_MESSAGE_SENDER_ID: string;
+   VITE_APP_ID: string;
+   VITE_MICROSOFT_TENANT_ID: string;
+ }

+ interface ImportMeta {
+   readonly env: ImportMetaEnv;
+ }
```

### firebase.ts

Firebaseの初期化処理になります
殆どよくみる処理ですが、`OAuthProvider`部分が追加しています

```ts:src/configs/firebase.ts
import { initializeApp } from "firebase/app";
import { getAuth, OAuthProvider } from "firebase/auth";

const firebaseConfig = {
  apiKey: import.meta.env.VITE_API_KEY,
  authDomain: import.meta.env.VITE_AUTH_DOMAIN,
  projectId: import.meta.env.VITE_PROJECT_ID,
  storageBucket: import.meta.env.VITE_STORAGE_BUCKET,
  messagingSenderId: import.meta.env.VITE_MESSAGE_SENDER_ID,
  appId: import.meta.env.VITE_APP_ID,
};

const app = initializeApp(firebaseConfig);
const provider = new OAuthProvider("microsoft.com");

provider.setCustomParameters({
  tenant: import.meta.env.VITE_MICROSOFT_TENANT_ID,
});

const auth = getAuth(app);

export { auth, provider };
```

インスタンス作成時に`microsoft.com`を引数として渡してあげます
また`setCustomParameters`にMicrosoftEntralIDのテナントIDを指定してあげます

```ts
const provider = new OAuthProvider("microsoft.com");

provider.setCustomParameters({
  tenant: import.meta.env.VITE_MICROSOFT_TENANT_ID,
});
```

### useAuth.ts

先ほど`src/configs/firebase.ts`で定義した`auth`と`provider`を仕様して認証処理を作成していきます
実装時は`signInWithPopup`に`auth`と`provider`を引数として渡してあげるとMicrosoftの認証処理を実装してくれます

```ts:src/hooks/useAuth.ts
import { signInWithPopup, signOut } from "firebase/auth";
import { useCallback, useState } from "react";
import { auth, provider } from "../configs/firebase";

type UseAuthReturn = {
  login: () => void;
  logout: () => void;
  isLogin: boolean;
};
type UseAuth = () => UseAuthReturn;

export const useAuth: UseAuth = () => {
  const [isLogin, setIsLogin] = useState(false);

  const login = useCallback(async () => {
    await signInWithPopup(auth, provider)
      .then((r) => {
        setIsLogin(true);
        console.log(r);
      })
      .catch((e) => console.error(e));
  }, []);

  const logout = useCallback(() => {
    signOut(auth);
    setIsLogin(false);
  }, []);

  return { login, logout, isLogin };
};
```

### App.tsx

`useAuth.ts`で定義した認証処理を呼んであげます

```tsx:src/App.tsx
import "./App.css";
import { useAuth } from "./hooks/useAuth";

function App() {
  const { login, logout, isLogin } = useAuth();

  return (
    <>
      {isLogin ? (
        <button onClick={logout}>ログアウト</button>
      ) : (
        <button onClick={login}>ログイン</button>
      )}
    </>
  );
}

export default App;
```

一先ずコードは実装完了です

次はFirebaseとMicrosoftを設定していきます

:::note warn
Firebaseは既にアカウントがあること、Microsoftは社内用アカウントがあることを前提にしています
:::

## Firebase

### 1. プロジェクト作成

「プロジェクトを作成する」をクリックしてください

![CleanShot 2025-03-02 at 11.48.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/80a9e31f-b050-427b-be96-a8166c652c3c.png)


### 2. プロジェクト名設定

作成するプロジェクトに合わせて名前を入力してください

![CleanShot 2025-03-02 at 16.00.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/a2074f27-f329-487c-95ab-f4a47f0d75fe.png)

### 3. Geminiの有効化

ここは作成するプロジェクトに合わせて有効化するか決めてください

![CleanShot 2025-03-02 at 11.51.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/6f8328fe-f383-4000-bb0c-2d1fdd233151.png)

### 4. アナリティクス有効化

今回は不要のためアナリティクスを無効化していますが、作成するプロジェクトに合わせて有効にしてください

![CleanShot 2025-03-02 at 11.52.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/c6c77b09-a3d8-4f19-82d9-1edd130bb426.png)

問題なければプロジェクトを作成してください

![CleanShot 2025-03-02 at 11.53.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/1dcd20f6-98d0-4649-adea-fdfcb57cc0da.png)


### 5. アプリ追加

プロジェクトトップ画面にて赤枠をクリックしてアプリを追加していきます

![CleanShot 2025-03-02 at 12.25.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/252acb37-5689-4b00-8612-45a86697828d.png)


### 6. アプリ名

ここもプロジェクト名と同様に個々人で決めてください

![CleanShot 2025-03-02 at 12.27.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/48dfba2a-4cd2-4226-9706-069284881376.png)

### 7. 環境変数

「アプリを登録」をクリック後、環境変数が表示されるのでコピーしてReactプロジェクトの.envファイルに記載してください

![CleanShot 2025-03-02 at 12.29.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/9002f411-23e5-49c1-ad6e-f547037d2369.png)

### 8. リダイレクトURLのメモ

#### 8-1. Authentication画面へ遷移

赤枠で囲っている箇所をクリックして画面が遷移したら「始める」をクリックしてください

![CleanShot 2025-03-02 at 12.49.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/74599374-5091-4a52-bfce-3f5b9c6b1bb4.png)

![CleanShot 2025-03-02 at 12.50.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/aa69c417-d674-4195-9470-b704129e6fcd.png)

#### 8-2. ログインプロバイダの選択

プロバイダを選択画面に遷移したら`Microsoft`をクリックしてください

![CleanShot 2025-03-02 at 21.03.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/fd32459a-4ffd-40a5-a5d2-ac7b1cf71952.png)

#### 8-3. リダイレクトURLコピー

モーダル表示されたらリダイレクトURLが表示されているのでコピーしてどこかにメモしてください

![CleanShot 2025-03-02 at 21.02.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/c42248a7-d439-43bd-959e-5a290964b834.png)


`アプリケーション`と`アプリケーションシークレット`の設定は`Microsoft`の設定後に行います

## Microsoft

### 1. Microsoft Entral IDにアクセス
`Microsoft Azure`にアクセスしたら「Microsoft Entral ID の管理」の「ビュー」をクリックしてアクセスします

![CleanShot 2025-03-02 at 15.15.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/46e69c71-a796-41dd-979e-579f81947445.png)

### 2. テナントID

`Microsoft Entral ID`にアクセスしたらテナントIDが表示されているのでコピー、Reactプロジェクトの.envに記載してください

![CleanShot 2025-03-02 at 21.30.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/ad6f0046-33d3-4bb3-8294-97bf06715476.png)


### 3. アプリの登録

左のメニューから管理 → アプリの登録の順でクリックして画面遷移したら画面上の新規登録をクリックします

![CleanShot 2025-03-02 at 15.26.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/311d7482-921a-4d58-ad17-d977e9231552.png)

登録画面が表示されたら

* 名前
    * プロジェクトに合う名前を入力してください
* サポートされているアカウントの種類
    * 今回は社内アカウントのみログイン出来るようにするため「この組織ディレクトリのみに含まれるアカウント」を選択します
* リダイレクトURL
    * ドロップダウンメニューは「Web」、URLは先ほどコピーしてメモしたFirebaseのリダイレクトURLを入力してください

入力完了したら「登録」をクリックして登録してください

![CleanShot 2025-03-02 at 16.03.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/4f807955-bf2b-445d-bf8d-ff0aab9e0fdc.png)

### 4. アプリケーションIDのメモ

登録が完了したらアプリのトップ画面が表示されて`アプリケーションID`が画面上に表示されているのでコピーしてどこかにメモしてください

![CleanShot 2025-03-02 at 17.42.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/1f9c8145-1666-4de5-a575-f9fbe3ab0f5d.png)

### 5. クライアントの作成

左のメニューから管理 → 証明書とシークレットの順でクリックして画面遷移したら画面中央辺りの「新しいクライアント シークレット」をクリックします
すると右に追加用フォームが表示されるのでデフォルトのまま「登録」をクリックしてください
もし変更したい場合は作成するプロジェクトに合わせて設定してください

![CleanShot 2025-03-02 at 17.45.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/d882b5cb-e235-404e-928d-fc188f4dddb2.png)

### 6. アプリケーションシークレットのメモ
作成したクライアントが表示されているので「値」と書かれているカラムをコピーしてどこかにメモしてください
「シークレット」と書かれているカラムではないので注意してください

![CleanShot 2025-03-03 at 07.23.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/8f5b72e6-1327-48aa-a21d-6aab341e2a63.png)

### 7. アクセス許可設定

左のメニューから管理 → APIのアクセス許可の順でクリックして画面遷移したら画面中央辺りの「アクセス許可の追加」をクリックします
すると右から「APIアクセス許可の要求」が表示されるので「Microsoft Graph」をクリックしてください

![CleanShot 2025-03-02 at 17.54.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/be6572d2-7d41-4116-9a8f-b82597f6ca2e.png)

画面が切り替わったら「委任されたアクセス許可」をクリック、下から「email」を選択して「アクセス許可の追加」をクリックして設定してください

今回は「email」だけですが、他にも様々な許可が可能です
物によっては自分自身のアカウントよりも上位権限を持つアカウントから許可を得ないと使えない設定があるので注意が必要です

![CleanShot 2025-03-02 at 17.56.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/b31e7899-b006-4c7f-80c4-2ceb9d6d8aed.png)

### 8. メモしたアプリケーションIDとアプリケーションシークレットを設定

`Firebase Authentication`に戻りメモしたメモしたアプリケーションIDとアプリケーションシークレットをそれぞれ入力して「保存」をクリックしてください

![CleanShot 2025-03-02 at 17.51.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311195/fe709dbb-7574-4f8c-a968-180151d65973.png)

これで全ての設定が完了です

## 動作確認

:::note warn
動作する動画は撮れないため実際に手元で動作させて確認してみてください
:::

ここまで設定したらローカルサーバーを起動して実際にログインしてみてください
実際に社内で使用しているMicrosoftアカウントでログインが行えるはずです

# 最後に
`Firebase + Microsoft`で認証機能実装はやってみると簡単ではあるものの情報が少ない実装方法だったので
今後似た実装するエンジニアの手助けとなる1記事になれば幸いです