見出し画像

ServiceWorkerでFirebaseAuthenticationのセッション管理

FirebaseAuthenticationを最近触っている。
とても便利。便利通り越して感動。
もうこれなしでは、生きていけない体になってしまった。

そんなFirebaseAuthenticationをSSRモードのnuxtで利用しようとした時、
セッション管理でハマったので、自分の理解としてまとめる。

nuxtServerInitでログイン判定を行いたい

SSRで作成しているので、当然 nuxtServerInit でログイン判定を行いたい。
firebaseでログインしていたら、nuxtServerInitでstoreにuidなりidTokenなり、投げたくなるのが人の性ってもんじゃないですか。

だけど、firebaseの認証情報はIndexedDBに保存されるので、
nuxtServerInitの時点では認証情報は取得できない。
取得できないということは、ログイン判定が行えない。
ログイン判定が行えないということは、絶望するしかない。悲しい。

cookieにIDTokenを保存する?

cookieはserverにも投げられるので、IDTokenをcookieに保存すれば
nuxtServerInitでも受け取れるぞ。

それはそうなんだけれど、firebaseのIDTokenは有効期限が1時間。
すぐに有効期限が切れてしまうし、有効期限が切れた時、
IDTokenをrefreshするためのRefreshTokenまでcookieに入れるとかしたくない。

というか、IDTokenのrefreshは、そもそもSDKが隠蔽している箇所だから、
自分ではやりたくない。というかできない。
nuxtServerInitで、SDK使わずに、IDTokenが有効かどうか、無効だったらrefreshして、とか無理ゲーである。

ServiceWorkerでセッションを管理する

やっと本題。
ていうか、ここまでのこと、ぜーんぶ公式のドキュメントにちゃんと書いてあるんだけどね。
すごい。ありがとう。Firebaseのドキュメントを作ってくれている人!読解力が無くてごめんなさい!

さて、ServiceWorker。名前は聞いたことはあったけど、使ったことはないので調べてみる。

・ブラウザにインストールして使用する
・インストールされたServiceWorkerは別スレッドでJSを動かすことができる
・ServiceWorkerからIndexedDBにアクセスできる
・ServiceWorkerにはライフサイクルがある

という、ざっくりとした理解。

じゃあ、次はFirebaseのドキュメントを読み解く。

アプリに対するフェッチ リクエストはすべてインターセプトされ、使用可能であれば ID トークンがヘッダーを介してリクエストに追加されます。サーバー側では、リクエスト ヘッダーに ID トークンがあるかどうか確認され、検証後に処理されます。Service Worker スクリプトで、フェッチ リクエストがインターセプトされ、変更されます。

なるほどわからん。というか盛大に勘違い。

フェッチリクエストと書いてあるので、
nuxtから外部APIを叩くときのフェッチをインターセプトするのかと思っていた。

いやいや、僕がやりたいことは、nuxtServerInitでIDTokenを受け取りたいだけであって、外部APIは関係ないのですよ。一体何がしたいんだServiceWorkerさん。

と、すべての責任をServiceWorkerになすりつけていたのだけど、
実際に試してみると、このフェッチのインターセプトは、
nuxtに対するリクエストをインターセプトするということだった。

つまり、流れとしては、

1. ページに初めて訪れたときにServiceWorkerがインストールされる
2. 以降のnuxtに対するリクエストは、ServiceWorkerによりインターセプトされる(nuxtに到達する前にServiceWorkerの処理が走る)
3. インターセプトした処理の中で、Firebase SDKを通しIDTokenを取得する(この時、ServiceWorkerからはIndexedDBにアクセスできるので、認証情報にも当然アクセスできる。IDTokenの有効期限も更新される。)
4. 取得したIDTokenを、リクエストヘッダに追加する
5. IDTokenを追加したリクエストヘッダで、nuxtへ流す
6. nuxtに到達し、nuxtServerInitが呼び出される
7. リクエストヘッダには4で追加されたIDTokenが含まれているので煮るなり焼くなり好きにする

ということだと、理解した。は〜、難しい。

細かい実装については、下記によくまとまっていたので割愛。
大変助かりました。ありがとうございます。


この記事が気に入ったらサポートをしてみませんか?