OIDC トークンの管理と検証
取得したトークンはこれを提示するだけでログインできたり、各リソースにアクセスできたりしてしまう機密情報であるため、取得したあとの扱いも重要です。
トークンの有効期限
ここまでに見てきたトークンには「認証」(誰がログインしている?)を担う ID Token と「認可」(なにをして良い?)を担う Access Token がありました。
これらのトークンには漏えい時の被害を最小限に抑えるために有効期限が設定されています。漏えい時の被害の大きさによって有効期限の設定は様々ですが、一般的に ID Token では 1 時間から 24 時間、Access Token では 5 分から 60分とすることが多いです。
しかし、このように有効期限が短くなると頻繁に再ログイン(トークン交換)をやり直して、最新のトークンを取得し直す必要が生じてしまい、実用上の不便が大きくなってしまいます。
これを解決するために導入されているのが「Refresh Token」です。
Refresh Token
Refresh Token は、期限切れになった Access Token を、ユーザーに再ログインさせずに更新するためのトークンです。
クライアント(RP)が認可サーバー(IdP)のトークンエンドポイントにだけ送り、「新しい Access Token をください」と依頼するために使います。
Refresh Token には 7 日から 30 日など長い有効期限をもたせることが一般的です。
Refresh Token は ID Token や Access Token と違って、API リクエストで頻繁に通信に載せるようなトークンではないため、正しく管理していれば比較的漏えいリスクが低いとされています。
もちろん、Refresh Token が漏洩すれば他のトークンを取得可能であるため、厳重な管理が前提となります。
offline_access スコープ
offline_access スコープは、「Refresh Token を要求する」ことを伝えるためのスコープです。
認可リクエストの scope に offline_access が含まれ、リソースオーナーが同意した場合に、トークン応答へ Refresh Token が付きます。要求しなければ Refresh Token は発行されず、ID Token や Access Token の期限が切れたあとは、ユーザーに再度ログインしてもらう必要があります。
RFC 技術仕様
Refresh Token による更新は OAuth 2.0(RFC 6749)の refresh_token グラントに示されています。OIDC では、オフラインアクセスのために offline_access スコープを使うことが OpenID Connect Core 1.0 に定められています。
JWT と opaque token
トークンの形式には、大きくわけて 2 種類があります。
JWT
2 章 で見た JWT は、クレーム(誰向けか、いつまで有効か、など)がトークン自身に入っている形式です。改ざん検知用の電子署名が付いているため、検証する側は 公開鍵さえ手元にあれば、IdP に毎回問い合わせなくても 内容を信頼できます。
ID Token は仕様上 常に JWT ですが、Access Token や Refresh Token は IdP の実装によって次の opaque token である場合があります。
opaque token
opaque token(不透明トークン)は、十分に推測困難なランダムな文字列です。Session ID と同じく、文字列自体には検証する側が読める意味がありません。誰に発行したか、どの権限があるか、失効していないかは、発行した IdP だけが知っています。
したがって opaque なトークンを検証するには、リソースサーバーが IdP に「このトークンはまだ有効か」と問い合わせる必要があります。この問い合わせを イントロスペクション(Introspection)と呼びます。
JWT と opaque token の比較
JWT のメリットは、リソースサーバーへのアクセスが有るたびに IdP にイントロスペクションを行う必要がない点です。opaque token の場合、トークン検証には必ず IdP への通信が必要となるので、IdP 側への負荷も大きくなるほか、ネットワークを経由することによる避けられない処理時間のオーバーヘッドが生じます。
一方、opaque token のメリットは、IdP 側が主体的にトークンを失効させられる点にあります。攻撃発生時に素早くトークンを無効化できるため、金融系等の攻撃ダメージ軽減を重視するシステムでは採用されやすいといえます。
Nogiku のトークン形式
Nogiku の Access Token は、認可リクエスト時に resource パラメータを付与した場合(推奨)に JWT を、そうでない場合には opaque token を発行します。 また、Refresh Toten は、常に opaque token を発行します。
リソースサーバーによる検証
クライアントが Access Token を添えて API を呼んだとき、リソースサーバーはデータを返す前にそのトークンを検証する必要がありました。ここでは、この検証方法の詳細を見ていきましょう。
検証の手順は、受け取った Access Token が JWT か opaque かで分かれます。
JWKS による検証(JWT)
JWT の署名検証に使う公開鍵は、IdP が JWKS(JSON Web Key Set)として公開します。4 章 の Discovery メタデータにある jwks.json(Nogiku Auth では /jwks)がそれです。
リソースサーバーは JWKS から公開鍵を取得し、少なくとも次を確認します。
| 確認すること | 意味 |
|---|---|
| 署名 | 改ざんされていないこと。鍵は JWT ヘッダーの kid で選ぶ |
iss | 想定している IdP が発行したこと |
aud | このリソースサーバー 宛であること |
exp | 有効期限内であること |
scope | 要求された操作に必要な権限が含まれていること |
aud
ID Token の aud は RP の client_id です。
一方、Access Token の aud は、リソースサーバーを識別する値(Audience)です。
JWKS の公開鍵は署名の 検証 に使うものであり、秘密ではありません。毎回 IdP へ取りに行く必要はなく、鍵の識別子(kid)ごとにキャッシュするのが一般的です。
公開鍵は定期的にローテーション(変更)されるため、未知の kid を受け取ったときには最新の公開鍵を取得しに行くような実装にする必要があります。
イントロスペクション(opaque token)
opaque な Access Token の場合、リソースサーバーは自身でトークンの有効性を検証できません。このときは IdP の イントロスペクション(introspection)エンドポイントにトークンを送り、発行者である IdP に有効性を問い合わせます。
典型的な応答には、次のような情報が含まれます。
active… まだ有効かどうか(失効・期限切れならfalse)sub… 誰のトークンかscope… どの権限があるかexp… いつまで有効か
Nogiku での検証
Nogiku のリソースサーバー(例: Nogiku Access API)は、Access Token を JWT として扱い、Nogiku Auth の JWKS で署名を検証したうえで、iss と aud が想定どおりかを確認します。連携するリソースサーバーを実装するときも、同じ確認が必要です。