🔥
【有効期限に注意】SPAでfirebaseのidTokenを使ってAPIリクエストする
firebase-authのidTokenをAPIリクエスト時にheaderのAuthorizationに渡して認証するという実装をした時の備忘録です。
ざっくり構成
APP: 計測や商品管理のできるダッシュボード
FRONT: React
API: REST
AUTH: firebase idToken
困った点
idTokenの有効期間は1時間なので、初期描画の際に取得しておくだけでは認証エラーが割と頻発する(今回の実装ではバックエンドから401が返るようになってます)
対応の選択肢
下記のどちらかかなと
- フロントエンドでリクエスト前に毎回idTokenを取得し直して認証する
- リクエストして401が返却されたらidTokenを取得してリトライ
各対応のデメリット
「リクエスト前に毎回idTokenを取得」
- 無駄なtoken取得メゾットを呼ぶことになる
「401が返却されたらidTokenを取得してリトライ」
- tokenをグローバルステートで管理する必要がある
- リトライ+state更新するのと、リクエストの引数に毎回stateで持っているidTokenを渡し、headerに設定する必要がある
と思っていて、複雑化させたくない気持ちが強かったので、「リクエスト前に毎回idTokenを取得」 する方針で実装することにしました。
ファイルの中身
細かい詳細は省きざっくりですが
firebaseのwrap用ファイル
import firebase from 'firebase/compat'
import firebaseApp from 'firebase/compat/app'
import * as firebaseAuth from 'firebase/auth'
const firebaseConfig = {
//configの内容
}
firebaseApp.initializeApp(firebaseConfig)
firebase.auth().setPersistence(firebaseApp.auth.Auth.Persistence.LOCAL)
export const auth = firebaseAuth
export type FireBaseUser = firebaseAuth.User | null
初期化と認証用のモジュールとtypeをwrapしてます
axiosをクライアント化してwrapしているファイル
import _axios from 'axios'
import { auth } from '../firebase'
const client = _axios.create({
baseURL: `${process.env.REACT_APP_PUBLIC_SITE_URL}`,
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
responseType: 'json',
})
client.interceptors.request.use(async (request) => {
//リクエスト前に毎回idTokenを取得する
const idToken = await auth.getAuth().currentUser?.getIdToken()
request.headers.Authorization = idToken
return request
})
リクエスト前に何か処理を行いたい場合は、interceptors.request
を使います
この中でidTokenを取得してheaders.Authorizationに設定します。
これでidTokenはいつでもフレッシュになるので、有効期限に関して注意する必要がなくなりました
有効期限を逐一チェックしてidTokenを取得するか切り分けるっていう手もあると思いますが、今回は選択肢に入りませんでした。
迷ったらsimple is bestの精神でやってます。
ありがとうございました。
Discussion