Firebase(v9) から取得したIDトークンをサーバサイド(Node.js)で検証したけど、色々調べたのは時間の無駄だった備忘録

# 概要
Express等で簡単に作ったAPIとの通信をセキュアにするため、Firebase Authenticationの```getIdToken()```メソッドを使おうと思ったら、v8でのnamespacedな書き方しか見つからなかったのv9でのmodularな記述方法を探した。

実はv8っぽい書き方が動かないというのがそもそも勘違いだったのだが、v9っぽくモジュール化されたメソッドでも同様のことができるので、雑にだが備忘として残しておく。

## 出来上がり
最初に結論をば
web v9っぽいidTokenの所得方法はこう
```v9.js
import { getAuth, getIdToken } from "firebase/auth";

const auth = getAuth()
const user = auth.currentUser
const idToken = await getIdToken(user, true)

```
ちなみに、[公式の簡単にアクセスできる場所](https://firebase.google.com/docs/auth/admin/verify-id-tokens?hl=ja#retrieve_id_tokens_on_clients)にはこう書いてある（2022/7/31時点）
v9っぽい書き方ではないが、v9を使っていても<B>ちょっと手直しすれば普通に動く</B>（firebase.auth()の代わりにgetAuth()を使えばok）![ID_トークンを検証する_ _ _Firebase_Authentication.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1741746/d2a4de04-e8b4-a582-ea37-ce707762ee91.png)


つまり、v8っぽくもv9っぽくも書ける仕様になっていました

# そもそもgetIdTokentって？
Firebase Authenticationにあるメソッド。公式ドキュメントは[こちら](https://firebase.google.com/docs/auth/admin/verify-id-tokens?hl=ja)
Firebaseで生成したtokenをクライアントからサーバーサイドに送付し、そのtokenが正しく生成されたものであるかどうかを確認することで、悪意のあるリクエストでないことを保障する方法。
所謂JWT(JSON Web Token)による認証


## 問題点
しかしながら、<B>公式のパッと見えるところには、v8（namespaced）でのサンプルコードのみが記載されており、v9(modular)での書き方がわからない</B>

以下、サンプルコード
```sample.js
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
  // Send token to your backend via HTTPS
  // ...
}).catch(function(error) {
  // Handle error
});
```

「JWTなんてもう使うな」ってことなんかな・・・？とちょっと不安になる。
お手軽にセキュリティを強化できるので、簡単なAPIには使いたいのだが・・・

# メソッドを探す
v9っぽいmodularな書き方くらいあるはずだ・・・！
とりあえず探してみました。
## modularのメソッド
v9のドキュメントの中にあった。[公式ドキュメント](https://firebase.google.com/docs/reference/js/auth.md#getidtoken)



こんな風に使えるようだ
```v9.js
import { getAuth, getIdToken } from "firebase/auth";

const auth = getAuth()
const user = auth.currentUser
const idToken = await getIdToken(user, true)

```

## Userクラスのメソッド(namespaced)
こっちもv9のドキュメントの中にあった
[公式ドキュメント](https://firebase.google.com/docs/reference/js/auth.user.md#usergetidtoken)
こちらはこのように使える
```v8.js
import { getAuth } from "firebase/auth";

const auth = getAuth()
const idToken = await auth.currentUser.getIdToken(true)
```

何が違うんや・・・？

## ということで、比較してみる
以下はそれぞれの公式ドキュメントのメソッドの記述

### getIdToken（）
>Firebaseサービスに対してユーザーを識別するために使用されるJSONWebトークン（JWT）を返します。
有効期限が切れていない場合、または5分以内に有効期限が切れない場合は、現在のトークンを返します。それ以外の場合、これによりトークンが更新され、新しいトークンが返されます。
>```modular.js
>export declare function getIdToken(user: User, forceRefresh?: boolean): Promise<string>;
>```

### User.getIdToken（）
>Firebaseサービスに対してユーザーを識別するために使用されるJSONWebトークン（JWT）を返します。
有効期限が切れていない場合、または5分以内に有効期限が切れない場合は、現在のトークンを返します。それ以外の場合、これによりトークンが更新され、新しいトークンが返されます。
>``` namespaced.js
>getIdToken(forceRefresh?: boolean): Promise<string>;
>```
### Userクラスのインスタンスを引数に取るかインスタンスのメソッドかが違うだけで、説明文が全く一緒。笑


実際に、両方のメソッドで同じtokenが返ってくることを確認できる。
![import_meta_env_VITE_APP_TITLE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1741746/a0ad7058-0d09-8146-8380-6bdc738ae8e8.png)

つまり、私のmodularなgetIdTokenを探す旅は見事に<B>時間の無駄</B>だったということである・・・

# サーバーサイドでの検証
ここからはv8とかv9とか関係ないので、完全に[公式ドキュメント](https://firebase.google.com/docs/auth/admin/verify-id-tokens?hl=ja#verify_id_tokens_using_the_firebase_admin_sdk)通り
Firebase Adming SDKを設定し（[参考](https://firebase.google.com/docs/admin/setup?hl=ja)）
```verifyIdToken()``` メソッドを使用して ID を確認できればok
```Node.js
// idToken comes from the client app
getAuth()
  .verifyIdToken(idToken)
  .then((decodedToken) => {
    const uid = decodedToken.uid;
    // ...
  })
  .catch((error) => {
    // Handle error
  });
```
これにて、クライアントから飛ばしたtokenの検証は完了です

# まとめ
クライアントでのidTokenの取得について、公式ドキュメントには
v8(namespaced)チックな記述方法が載っているが、
v9(modular)チックな記述方法でも同様のことができることがわかった。

v8チックな書き方でも普通に使えるので、時間を無駄にした感は強い。笑