CODE-416 リフレッシュトークン調査
- こっち優先だったの今知った, remark 爆速でやる
subtask
別タブとログイン状態を共有する: https://idh-pro.backlog.com/view/CODE-416
-
バグの再現
- アクセストークン更新時にverifyのエラーが出るらしい
-
原因
-
一つのページで多重にreq飛ぶからraceしているのもやだな
-
修正
現在は
- token, exp: Vuex Store(persisted on sessionStorage)
- refeshToken: cookie
に保存している. sessionStorage は永続化されないので新規タブではアクセストークンが取得できない. そこで, 複数タブが認証状態を得る方法として
-
token, refreshToken を Vuex Store(on-memory) に
各タブごとに独立して token pair を管理する. この方法では APIサーバーで token pair を複数管理しなければならない. 現在は各ユーザーに対して1つのみのリフレッシュトークンを保存できる. 複数保存するには, リフレッシュトークンをJWT形式にして claim に一意なidを持たせて, そのidを主キーとしてDBに保存する. -
token, refreshToken を localStorage にする
localStorageにすることによって, タブ間でアクセストークンを共有出来る.
安全性
localStorage = sessionStorage < cookie(http-only) < Session
WebアプリケーションでJWTをセッションに使う際の保存先は(自分なりに説明できれば)どちらでもよいと思います - 日々量産
- XSSの前には無力
PR
変更点
- (API)
GET /userのレスポンスにuserIdを含めました- 理由: ユーザー情報取得時に
userIdが含まれておらず「退会済みユーザー」と表示されていたから
- 理由: ユーザー情報取得時に
- (バックエンド)
RefreshTokenモデルはrefreshTokenIssuedAtではなく,refreshTokenExpiresAtを持つように - (バックエンド) 単体テストのコンパイルエラーを修正
- (フロントエンド) アクセストークン, リフレッシュトークンを localStorage に保存するように
- (フロントエンド) ルートコンポーネントの
mounted()で認証情報があるならユーザーデータを取得するようにしました
お手すきの際にレビュー・ご確認のほどお願いします.
認証情報の保管方法について
現在は
- アクセストークン, 有効期限: Vuex Store(persisted on sessionStorage)
- リフレッシュトークン: Cookie(
http-only属性なし)
に保存されていました. sessionStorage は永続化されないので新規タブではアクセストークンが取得できません. そこで, 複数タブが認証状態を得る方法として
-
token, refreshToken を Vuex Storeに
各タブごとに独立して認証情報を管理する. この方法ではAPIサーバーで ユーザーに対して認証情報を複数管理しなければならない(現在はユーザーに対し1つの実装).
複数保存するには, リフレッシュトークンをJWT形式にして claim に一意なidを持たせて, そのidを主キーとしてDBに保存することで実現できます. -
token, refreshToken を localStorage にする
localStorageにすることによって, 永続化され複数タブで同一の認証処理を使うことができます. 安全性としても sessionStorage やhttp-only属性なしCookieと同程度(開発者コンソールで見える, XSSで取得でされてしまう) であり, アクセストークンの有効期限も十分短いのでこちらを採用しました.
検討事項として, タブAでログアウトするとタブBの方で認証エラーで403が出ることです. トップページに戻る等でエラーハンドリングしたほうが良さそうです.
タブの挙動
- アクセストークンの期限が切れて or アクセストークンが無くて 403
- 長時間放置後リクエスト
- アクセストークン更新APIでPreAuthしてしまっている?
- -> no, ignoreされていた
- アクセストークン更新APIでPreAuthしてしまっている?
- 長時間放置後リクエスト