トークンとは?
不透明トークンを紹介する前に、トークンとは何かを理解することが重要です:
トークンは、当事者間で安全な情報を表現し伝達するために使用され、インターネット上で行われる大多数の 認証 (Authentication) および 認可 (Authorization) プロセスをサポートします。Webサービスで最も一般的なトークンのタイプは、 JSON Web Token (JWT) と不透明トークンです。
不透明トークンとは?
不透明トークンは、アクセスできない独自のフォーマットのトークンであり、通常はサーバーの永続ストレージ内の情報を識別するための識別子を含んでいます。
不透明トークンはトークンが取り得る形式の一つであり、 アクセス トークン や リフレッシュ トークン として存在することができます。不透明トークンのフォーマットはそのissuer (発行者) によって決定され、通常はデータベース内の特定の情報を取得し識別するために使用される数字や文字の文字列です。以下は不透明トークンの例です:
M-oxIny1RfaFbmjMX54L8Pl-KQEPeQvF6awzjWFA3iq
一方、JWTはもう一つの一般的なトークンフォーマットです。これは、issuer (発行者) からの署名と共にすべてのclaim (クレーム) と情報を含むJSON文字列です。デフォルトでは暗号化されていませんが、 JSON Web Encryption (JWE) 標準を使用して暗号化することができます。JWTは通常暗号化されていませんが、署名の存在によりトークンの内容の完全性が保証され、JWT内のデータに完全な信頼を置くことができます。
JWTとは異なり、保護されたリソースで直接検証するために必要なすべての情報を含むJWTとは異なり、不透明トークンはリソースによって直接検証することはできません。代わりに、不透明トークンのissuer (発行者) (通常は 認可サーバー (Authorization Server) )による検証が必要です。この検証プロセスは通常 トークンインスペクション (Token introspection) と呼ばれます。
JWTとは?
不透明トークンとは対照的に、JWTは構造化され読みやすいフォーマットで情報を運ぶ自己完結型のステートレスなトークンです。
JWTは、header
、payload
、signature
の3つの部分で構成され、それぞれがBase64URLでエンコードされています。
以下はJWTの例です:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
header
にはトークンの種類と署名に使用されるアルゴリズムに関する情報が含まれています。例:{"alg": "HS256", "typ": "JWT"}
。payload
セクションには、ユーザーまたはauthorization (認可) に関する情報であるclaim (クレーム) が含まれています。ユーザーID、有効期限、スコープなどです。このデータはエンコードされていますが暗号化されていないため、トークンを持っている人は誰でもクレームをデコードして見ることができますが、署名を無効にせずに変更することはできません。仕様とauthorization server (認可サーバー) の設定に基づいて、さまざまなクレームをpayloadに含めることができます。これにより、トークンは自己完結型になります。例:{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}
。signature
は、header、payload、および指定されたアルゴリズムを使用して秘密鍵を組み合わせることで生成されます。この署名はトークンの完全性を検証し、改ざんされていないことを確認するために使用されます。
JWTは、authorization server (認可サーバー) とやり取りすることなく、クライアントまたは任意のサービスによってローカルで検証できるため、一般的に使用されます。これにより、複数のサービスがトークンの信頼性を独立して検証する必要がある分散システムにおいて、JWTは特に効率的です。
しかし、この利便性は、トークンのクレームが過度に露出しないようにする責任も伴います。クレームはトークンにアクセスできる人には見えるからです。また、JWTは通常短命であり、トークンのクレームに有効期限が含まれているため、トークンが無期限に有効でないことが保証されます。
不透明アクセス トークンの検証
不透明アクセス トークンは、認可サーバーに戻して検証することで検証されます。認可サーバーは発行されたトークンの状態を維持し、内部ストレージに基づいてトークンの有効性を判断できます。
- クライアントは認可サーバーにアクセス トークンを要求します。
- 認可サーバーは不透明トークンを発行します。
- クライアントはヘッダーに不透明トークンを含めてリソースアクセス要求を送信します。
- リソースプロバイダーはトークンを検証するために認可サーバーにトークンインスペクション要求を送信します。
- 認可サーバーはトークン情報で応答します。
JWTアクセス トークンの検証 (オフライン)
JWTアクセス トークンは、トークンの公開鍵にアクセスできるクライアントまたは任意のサービスによってオフラインで検証できます。
- リソースプロバイダーは、 OpenID Connect (OIDC) ディスカバリー (Discovery) から認可サーバーの公開鍵を事前に取得します。公開鍵はトークンの署名を検証し、その完全性を保証するために使用されます。
- クライアントは認可サーバーにアクセス トークンを要求します。
- 認可サーバーはJWTトークンを発行します。
- クライアントはヘッダーにJWTトークンを含めてリソースアクセス要求を送信します。
- リソースプロバイダーは、認可サーバーから取得した公開鍵を使用してJWTトークンをデコードおよび検証します。
- リソースプロバイダーはトークンの有効性に基づいてアクセスを許可します。
OIDCにおけるユースケース
OIDC ( OpenID Connect (OIDC) ) のコンテキストでは、不透明トークンとJWTは異なる目的を果たし、異なるシナリオで使用されます。
不透明トークン
- ユーザープロファイルの取得:
デフォルトでは、クライアントがリソースを指定せずにアクセス トークンを要求し、openid
スコープを含めると、認可サーバーは不透明アクセス トークンを発行します。このトークンは主にOIDC /oidc/userinfo
エンドポイントからユーザープロファイル情報を取得するために使用されます。不透明アクセス トークンを含むリクエストを受け取ると、認可サーバーは内部ストレージをチェックして関連するauthorization (認可) 情報を取得し、トークンの有効性を確認してからユーザープロファイルの詳細を返します。
- リフレッシュ トークンの交換:
リフレッシュ トークンは、クライアントと認可サーバーの間でのみ交換されるように設計されており、リソースプロバイダーと共有する必要はありません。そのため、リフレッシュ トークンは通常、不透明トークンとして発行されます。現在のアクセス トークンが期限切れになると、クライアントは不透明リフレッシュ トークンを使用して新しいアクセス トークンを取得し、ユーザーを再認証することなく継続的なアクセスを確保します。
JWTs
- IDトークン:
OIDCでは、IDトークンはユーザー情報を含むJWTであり、ユーザーを認証するために使用されます。通常、アクセス トークンと共に発行され、クライアントがユーザーのアイデンティティを確認できるようにします。例:
// IDトークンのデコードされたペイロード
{
"iss": "<https://auth.wiki>",
"sub": "1234567890",
"aud": "client_id",
"exp": 1630368000,
"name": "John Doe",
"email": "[email protected]",
"picture": "<https://example.com/johndoe.jpg>"
}
クライアントはIDトークンを検証してユーザーのアイデンティティを確認し、パーソナライズやauthorization (認可) の目的でユーザー情報を抽出できます。IDトークンは一度だけの使用に限られ、APIリソースのauthorization (認可) には使用されるべきではありません。
- APIリソースアクセス(アクセス トークンを使用):
クライアントが特定の リソースインジケーター (Resource indicator) を指定してアクセス トークンを要求すると、認可サーバーはそのリソースにアクセスするためのJWTアクセス トークンを発行します。JWTには、リソースプロバイダーがクライアントのアクセスを認可するために使用できるクレームが含まれています。例:
// JWTアクセス トークンのデコードされたペイロード
{
"iss": "<https://auth.wiki>",
"sub": "1234567890",
"aud": "<https://api.example.com>",
"scope": "read write",
"exp": 1630368000
}
リソースプロバイダーはクレームを確認することでリクエストを検証できます:
iss
: トークンが信頼できる認可サーバーによって発行されたことを確認します。sub
: トークンに関連付けられたユーザーを識別します。aud
: トークンが特定のリソースを対象としていることを確認します。scope
: ユーザーに付与された権限を確認します。