CODE-416 リフレッシュトークン調査

2022-12-19

  • こっち優先だったの今知った, remark 爆速でやる

subtask

別タブとログイン状態を共有する: https://idh-pro.backlog.com/view/CODE-416

現在は

  • token, exp: Vuex Store(persisted on sessionStorage)
  • refeshToken: cookie
    に保存している. sessionStorage は永続化されないので新規タブではアクセストークンが取得できない. そこで, 複数タブが認証状態を得る方法として
  1. token, refreshToken を Vuex Store(on-memory) に
    各タブごとに独立して token pair を管理する. この方法では APIサーバーで token pair を複数管理しなければならない. 現在は各ユーザーに対して1つのみのリフレッシュトークンを保存できる. 複数保存するには, リフレッシュトークンをJWT形式にして claim に一意なidを持たせて, そのidを主キーとしてDBに保存する.

  2. 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 は永続化されないので新規タブではアクセストークンが取得できません. そこで, 複数タブが認証状態を得る方法として

  1. token, refreshToken を Vuex Storeに
    各タブごとに独立して認証情報を管理する. この方法ではAPIサーバーで ユーザーに対して認証情報を複数管理しなければならない(現在はユーザーに対し1つの実装).
    複数保存するには, リフレッシュトークンをJWT形式にして claim に一意なidを持たせて, そのidを主キーとしてDBに保存することで実現できます.

  2. token, refreshToken を localStorage にする
    localStorageにすることによって, 永続化され複数タブで同一の認証処理を使うことができます. 安全性としても sessionStorage や http-only 属性なしCookieと同程度(開発者コンソールで見える, XSSで取得でされてしまう) であり, アクセストークンの有効期限も十分短いのでこちらを採用しました.

検討事項として, タブAでログアウトするとタブBの方で認証エラーで403が出ることです. トップページに戻る等でエラーハンドリングしたほうが良さそうです.

タブの挙動

  • アクセストークンの期限が切れて or アクセストークンが無くて 403
    • 長時間放置後リクエスト
      • アクセストークン更新APIでPreAuthしてしまっている?
        • -> no, ignoreされていた