JWT
リソース
やること
メモ
JWTとは
JSONをアクセストークンとして用いる
リソースサーバー(APIサーバなど)側である程度tokenの検証ができるので認可サーバーとDBへのアクセスが減り結果として負荷を抑えられるメリットがある
JWTの具体例
中身はこんなやつ。
code:header.json
{
"alg": "HS256",
"typ": "JWT"
}
code:payload.json
{
"exp": 1642386406,
"sub": "00000000-000-0000-0000-0000000000",
"email": "hoge@example.com",
"phone": "",
"app_metadata": {
"provider": "google",
"providers": [
"google"
]
},
"user_metadata": {
"email": "hoge@example.com",
"email_verified": true,
"full_name": "razoku lover",
"name": "n y",
"provider_id": "000000000000000000",
"sub": "000000000000000000000"
},
"role": "authenticated"
}
Claimとは
RFCで定義されているJSON内の標準的なキーと値のペア
issとかsubとかexpとか
Claimの種類
Public Claim Names
claimの衝突を避けるためにIANAで登録されている汎用claim
Registered Claim Names
Public Claim Namesのサブセット。一般的な用途で利用されるclaim。
Private Claim Names
issuerとaudienceの間で取り決められたルールに則り、独自に含めたいclaim。Registered Claim Namesと重複しないようにする必要がある。
Registered Claim Namesの種類
“iss” (Issuer) (Optional)
JWTの発行者を意味します。 値として文字列かURIを取ることができ、アプリケーション名やドメイン名が入ると思います。 値は大文字/小文字を区別して扱われます。
“sub” (Subject) (Optional)
JWTの用途を意味します。 値として文字列かURIを取ることができます。 値は大文字/小文字が区別され、同じIssuer内でユニーク、または全世界でユニークである必要があります。
“aud” (Audience) (Optional)
JWTの想定利用者を意味します。 値として文字列かURI、またはそれらの配列を取ることができます。 値は大文字/小文字が区別されます。
発行する側はJWTの発行要求をしてきた相手を識別する文字列やURIを入れ込み、 発行された側はAudience Claimが存在する場合は自分向けに発行されたJWTなのかどうかを検証することに用います。
“exp” (Expiration Time) (Optional)
JWTが失効する日時を意味します。 値としては、数値表現された日付となります。(例: “12345”)
失効する日時を表すUNIX時刻などを入れるのが良いと思います。
“nbf” (Not Before) (Optional)
JWTが有効になる日時を意味します。 取り得る値は”exp”と同様です。
“iat” (Issued At) (Optional)
JWTが発行された日時を意味します。 取り得る値は”exp”や”nbf”と同様です。
“jti” (JWT ID) (Optional)
JWTのユニーク性を担保するID値を意味します。 “jti”が異なるJWTは、全く別のJWTとして扱われます。 値は大文字/小文字が区別されます。
これ対応する形でJWTを構築すると例えばこのようになる↓ 各フィールドとその値を見比べてみると役割が理解しやすい。
code:json
{
"jti": "92f46647-90a2-4174-bca9-27d7f69a8fb7",
"sub": "AccessToken",
"aud": [
],
"exp": 1485320878,
"nbf": 1485317273,
"iat": 1485317278
}
これにPrivate Claimとしてkey名が被らないようにユーザ情報を含めたりする。
おまけ
AWS AmplifyのJWTの更新(silent refresh)がlocalstorageに保存されたrefresh_tokenで行われているのでセキュアでないというissueを見つけた。これに対応してた人もAWSを辞めてしまっているので現在も放置されているとのこと。
てかSilent Authenticationって何?
prompt=noneを使った認可コードのリクエスト使った認証。画面遷移などを介さずひっそりとセッションを確認してアクセストークンを再取得する仕組み。prompt=noneはOpen Connectに定義されたの認可リクエスト(redirectとかform_postとか)のうちの一つ。画面表示が行われないのでSPAのユーザー体験が損なわれない。ユーザーの裏側でセッションの確認が行われる。ユーザーがログインしてるか否かを確認するのに便利。ローカルストレージを使わないので悪意あるThird party JSに抜かれたりしないのでよりセキュア。
Refresh Token Roationとは?
Silent Authenticationで万事解決かと思いきやところがどっこい、近年のSafari ITP(tracking prevention)などThird party cookieがブロックされてしまっている環境ではSPA (iframe) <-> idpサーバ(Auth0等)ドメイン間でThird party cookieにあたり動かない場合がある。Auth0のカスタムドメイン機能を使えば回避できるがこれはエンタープライズプラン。
そこでRefresh Token Roation という手法が生まれた。これは有効期限(短め)つきのrefresh tokenをlocalstorageに格納するパターン。localstorageが危険なのは有効期限のないrefresh tokenをlocalstorageに格納していたのが原因だったので、これを有効期限つきにしてアクセストークン取得時にrotation(入れ替え)するようにすればlocalstorageを利用しても限りなく安全に扱えるだろうという話。