はじめに
JWT認証におけるaccess_tokenとrefresh_tokenの使い分けを見ながら、両者の違いを説明します。
説明しないこと
JWTはログイン機能でよく利用されます。
詳しいログイン機能の作成方法については解説しません。
JWTとは
JWTは(Json Web Token)の略で、JSON形式のデータに情報を格納したものをtoken化したものです。Webアプリケーションの認証(JWT認証)によく使われます。
JWTの仕組み
JWTはヘッダ.ペイロード.署名の3つに分けられ、.で区切られます。
# jwtの例
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE3NDAyOTQ5MTd9.feyNR9Itzv-58R0U3TFFUCD5yTcn_z3ucClFCKJkyg8
ペイロード部分にユーザーidなどを格納して、認証が必要な通信でheadersのAuthorizationに含めて送信します。payload部分は誰でも簡単に複合化することが可能なので、password等の機密情報を入れたりしてはいけません。 悪意のあるユーザーがpayloadを書き換えても、署名部分が合わなくなるので、改ざんを検知することが可能です。
access_tokenとrefresh_token
access_tokenとrefresh_tokenは使用されるタイミングが異なります。
tokenの構造等に違いがあるわけではありません。
JWTを使った認証方式の場合、access_tokenもrefresh_tokenもJWTです。
tokenを2つ使う理由はセキュリティの向上です。
※ refresh_tokenはuuidなどランダムな文字列を使用する場合もあります。JWTである必要はありません
2つのtokenを使用する理由
APIでやり取りをするアプリケーションの場合、リクエストの度にaccess_token(JWT)をサーバーに送信する必要があります。
つまりネットワーク上にaccess_tokenが流れる回数が増え、当然盗聴されるリスクも高まります。単純に盗聴する機会が増えるからです。
有効期限が1ヶ月のtokenが悪意のあるユーザに盗聴された場合、1ヶ月もの間不正ログインされる状態になります。頻繁にネットワーク上でやり取りされるaccess_tokenは有効期限を短く設定するのが望ましいです。
しかし、access_token単体の運用だと、頻繁にログインし直す必要があるため、ユーザー体験が悪くなります。
そこでrefresh tokenの登場です。
有効期限の考え方
例えば、refresh tokenの有効期限を1ヶ月。access_tokenの有効期限を1時間に設定します。
access_tokenの有効期限が切れた状態でアプリケーションを訪れた場合に、refresh_tokenを使用してaccess_tokenの再発行を行います。 以降のリクエストでは、access_tokenを利用して通信します。
再度access_tokenが切れた際にrefresh_tokenで再発行。 これを繰り返します。
これで、毎回の通信では有効期限の短いaccess_tokenを利用することでセキュリティリスクを下げ、access_tokenの有効期限が切れた時だけ、resresh_tokenによる再取得を実行することで、ユーザの利便性も確保することができます。
ユーザーが再度ログインする必要があるのはrefresh_tokenの有効期限が切れる1ヶ月後です。
refresh_tokenの保存と検証ステップ
JWT(access_token)を使用したAPI通信では、JWTをサーバ側で保持しませんが、refresh_tokenはDBに保存します。
refresh_tokenを使用した再検証時には、以下2つのステップでaccess_tokenの再発行を行います。
1 該当のrefresh_tokenを保持するユーザデータはあるか
2 refresh_tokenの有効期限は切れていないか
refresh_tokenをDBに保持しておくと、万が一refresh_tokenが流出した可能性のあるユーザが発生した場合に、該当のユーザーに紐づくrefresh_tokenのDBから削除することで、流出したrefresh_tokenの有効期限が残っていても無効化させることが可能です。
仮のaccess_tokenだけの運用をしていた場合、secret_keyを変更する必要が出てきます。 その場合全てのユーザのaccess_tokenが無効になります。
※ refresh_tokenは漏洩リスクを考えハッシュ化するのが望ましいです
refresh_tokenの取り扱い
access_tokenはJSONの戻り値として返したり、response headerとして返し、localStorageやRedux等の状態管理ライブラリで保存されます。
一方でrefresh_tokenはセキュアに管理するため、HTTPOnly Cookieで管理されます。
HTTPOnly CookieはJavaScriptからのアクセスできないCookieです。 XSSによる攻撃から守ることができます。
クロスドメイン(HTTPOnly Cookie)
注意点として、クロスドメイン環境の場合、safariはデフォルトでサードパーティ製Cookieをブロックします。
つまりsafariユーザーはrefresh_tokenを利用できないので、最後にAPI通信を行ってから1時間経つと毎回ログインする必要があります。
これを回避するにはrefresh_tokenもaccess_tokenと同じようにJSONやresponse headersでやりとりし、Content Security Policy (CSP)を厳密にするなどして、可能な限りのXSS対策を行うなど、別の手が必要です。
結論
refresh_tokenはaccess_tokenの再取得のために使われる。
access_token: 頻繁にネットワークに晒されるため、有効期限設定して漏洩した時のリスクを抑える
refresh_token: 有効期限を長めに設定するが、ネットワークに晒される回数は少ないため漏洩する危険性は少ない
参考