概要
Express等で簡単に作ったAPIとの通信をセキュアにするため、Firebase AuthenticationのgetIdToken()
メソッドを使おうと思ったら、v8でのnamespacedな書き方しか見つからなかったのv9でのmodularな記述方法を探した。
実はv8っぽい書き方が動かないというのがそもそも勘違いだったのだが、v9っぽくモジュール化されたメソッドでも同様のことができるので、雑にだが備忘として残しておく。
出来上がり
最初に結論をば
web v9っぽいidTokenの所得方法はこう
import { getAuth, getIdToken } from "firebase/auth";
const auth = getAuth()
const user = auth.currentUser
const idToken = await getIdToken(user, true)
ちなみに、公式の簡単にアクセスできる場所にはこう書いてある(2022/7/31時点)
v9っぽい書き方ではないが、v9を使っていてもちょっと手直しすれば普通に動く(firebase.auth()の代わりにgetAuth()を使えばok)
つまり、v8っぽくもv9っぽくも書ける仕様になっていました
そもそもgetIdTokentって?
Firebase Authenticationにあるメソッド。公式ドキュメントはこちら
Firebaseで生成したtokenをクライアントからサーバーサイドに送付し、そのtokenが正しく生成されたものであるかどうかを確認することで、悪意のあるリクエストでないことを保障する方法。
所謂JWT(JSON Web Token)による認証
問題点
しかしながら、公式のパッと見えるところには、v8(namespaced)でのサンプルコードのみが記載されており、v9(modular)での書き方がわからない
以下、サンプルコード
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のドキュメントの中にあった。公式ドキュメント
こんな風に使えるようだ
import { getAuth, getIdToken } from "firebase/auth";
const auth = getAuth()
const user = auth.currentUser
const idToken = await getIdToken(user, true)
Userクラスのメソッド(namespaced)
こっちもv9のドキュメントの中にあった
公式ドキュメント
こちらはこのように使える
import { getAuth } from "firebase/auth";
const auth = getAuth()
const idToken = await auth.currentUser.getIdToken(true)
何が違うんや・・・?
ということで、比較してみる
以下はそれぞれの公式ドキュメントのメソッドの記述
getIdToken()
Firebaseサービスに対してユーザーを識別するために使用されるJSONWebトークン(JWT)を返します。
有効期限が切れていない場合、または5分以内に有効期限が切れない場合は、現在のトークンを返します。それ以外の場合、これによりトークンが更新され、新しいトークンが返されます。modular.jsexport declare function getIdToken(user: User, forceRefresh?: boolean): Promise<string>;
User.getIdToken()
Firebaseサービスに対してユーザーを識別するために使用されるJSONWebトークン(JWT)を返します。
有効期限が切れていない場合、または5分以内に有効期限が切れない場合は、現在のトークンを返します。それ以外の場合、これによりトークンが更新され、新しいトークンが返されます。namespaced.jsgetIdToken(forceRefresh?: boolean): Promise<string>;
Userクラスのインスタンスを引数に取るかインスタンスのメソッドかが違うだけで、説明文が全く一緒。笑
実際に、両方のメソッドで同じtokenが返ってくることを確認できる。
つまり、私のmodularなgetIdTokenを探す旅は見事に時間の無駄だったということである・・・
サーバーサイドでの検証
ここからはv8とかv9とか関係ないので、完全に公式ドキュメント通り
Firebase Adming SDKを設定し(参考)
verifyIdToken()
メソッドを使用して ID を確認できればok
// 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チックな書き方でも普通に使えるので、時間を無駄にした感は強い。笑