JWTについて個人的にまとめる
JWTとは?
JWT(JSON Web Token)は、クレーム(claims)をJSONで表し、それをJWS(署名/MAC) のペイロードまたはJWE(暗号化) の平文として包装して運ぶためのフォーマットです。JWSを使えば改ざん検出と発行者の真正性を、JWEを使えば機密性(+完全性)が確保できます。MAC は対称鍵での完全性保護手段です。
どういう時に使われるのか
- OIDC / OAuth2 認証認可(IDトークン・アクセストークン)
- マイクロサービス認可
- Webhook 署名
- SSO
など…
jose
joseとは、Javascript Object Signing and Encryptionというワーキンググループです。
JSONベースの署名・暗号・鍵・アルゴリズム群を標準化したWGとなります。
以降、JWT(箱)・JWS(署名)・JWE(暗号化)・JWK(鍵)・JWA(アルゴリズム)という用語が頻出します。
JWTの構造
ヘッダ、ペイロードはjson、署名はバイト列で記述されており、それぞれをピリオド区切りのbase64urlでエンコードしたものとなります。
header(base64url).payload(base64url).signature(base64url)
上記がJWTの形式となります。これはbase64urlでエンコードされているため、検証の際にはデコードをする必要がありそれらをデコードするとjson形式で内容が確認できます。
ヘッダ
JWTのヘッダには、暗号化アルゴリズムや鍵の識別子が入ります。代表的な項目として、下記があります。
-
alg
(必須):署名(またはMAC)のアルゴリズム(例:RS256
/ES256
/EdDSA
) -
typ
:オブジェクト種別(例:"JWT"
) -
kid
:鍵の識別子(JWKS の公開鍵選択に使う)
ペイロード
ペイロードには、発行者や有効期限などの情報が入ります。
-
iss
(発行者) -
sub
(主体) -
aud
(受け手) -
exp
(有効期限) -
nbf
(この時刻より前は無効) -
iat
(発行時刻) -
jti
(トークンID)
署名
改ざん検出と発行者の真正性を保証します。
ここで、AWSのJWTのドキュメントを例に挙げます。
公式ドキュメントには下記のような記載があります。
ヘッダーAmazon Cognito がトークンの署名に使用したキー ID、
kid
、および RSA アルゴリズム、alg
。Amazon Cognito はRS256
のalg
でトークン署名します。kid
は、ユーザープールが保持する 2048 ビット RSA プライベート署名キーへの切り捨てられたリファレンスです。
ペイロードトークンクレーム。ID トークンでは、クレームには、ユーザー属性とユーザープール、iss
、およびアプリクライアント、aud
に関する情報が含まれます。アクセストークンのペイロードには、スコープ、グループメンバーシップ、ユーザープールがiss
として含まれ、アプリクライアントはclient_id
として含まれます。
署名署名は、ヘッダーやペイロードのようにデコード可能な base64url ではありません。JWKS URI で確認できる署名キーとパラメータから派生した RSA256 識別子です。
AWSではWebアプリケーションのユーザ管理としてAmazon Cognitoを利用するケースが多いと思いますが、Cognitoから発行されるJWTには上記の情報が含まれています。Cognitoの詳細は割愛しますが、Cognitoのユーザプール内のユーザに付与された属性を取得することも可能になります。
OIDC / OAuth2 認証認可の例
OIDC / OAuth2 認証認可の場合、IDトークン、アクセストークン、リフレッシュトークンがクライアントに渡されます。この際、IDトークンは必ずJWTの形式で送信され、アクセストークンはJWTの形式も可能ですが、その限りではありません。
Cognitoなどで認証されたクライアントはサーバからIDトークン、アクセストークン、リフレッシュトークンを渡されます。IDトークンは、ログインを行ったという証跡としてクライアントが保持します。
ログイン後にGETやPOSTなどのメソッドをサーバにリクエストすると思いますが、その際にアクセストークンをBearerというキーの値として渡してリクエストをしてログイン後のリクエストを完了させます。
また、リフレッシュトークンはユーザに再ログインをせずにアクセストークンをリフレッシュする役割を持ちます。
参考文献
Discussion