LoginSignup
26
10

More than 3 years have passed since last update.

初版: 2020/12/16
著者: 田畑義之, 株式会社日立製作所 (GitHubアカウント: @y-tabata)

はじめに

OSSのIAM(Identity and Access Management)製品で、OAuthの認可サーバとしても使えるKeycloakが、バージョン10.0.0でToken Revocation (RFC 7009)をサポートしました1。(ちなみに筆者がPR #6704でコミットしました。)
release_note.png

エンハンスリクエスト用のJIRAチケット2にも多数のVoteが集まっており、このToken Revocationがいかに渇望されていたかがわかります。
jira.png

今回は、OAuthの認可サーバにとって、このToken Revocationがいかに重要かということを説明しようと思います。Keycloakに関する詳細は、Think ITの連載「Keycloakで実現するAPIセキュリティ」をご参照ください。

本記事は、あくまで執筆者の見解であり、日立製作所及びRed Hatの公式なドキュメントではありません。

Token Revocation (RFC 7009)とは

Token Revocationとは、RFC 7009で定義されているトークン無効化方法です。認可サーバがtokenパラメータで渡されたトークンを無効にすることで、アプリケーション(RP)は以降当該トークンを用いたAPIコールないしトークンリフレッシュができなくなります。

Token Revocationリクエスト例
POST /revoke HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW

token=45ghiukldjahdnhzdauz&token_type_hint=refresh_token

ではログアウトとはどう違うのでしょうか。Keycloakは初期のころから、Logout Endpointを通じたログアウトをサポートしています。ログアウトした場合も、認可サーバがログアウトしたユーザのトークンを無効にすることで、アプリケーションは以降当該トークンを用いたAPIコールないしトークンリフレッシュができなくなります。

以降、ログアウトを引き合いに出しつつ、Token Revocationの必要性を説明していきます。

Token Revocationとログアウトの違い

近年、様々なアプリケーションのログイン画面で、「GitHubアカウントでログイン」や「Twitterアカウントでログイン」といったようなものをよく見かけるかと思います。
login_screen.png
出典: https://qiita.com/

これは、アプリケーションがGitHubやTwitterの認可サーバに認証を委譲していることを意味します。つまり、今や1つのユーザアカウントで複数のアプリケーションにログインするということは日常的に行われています。
multi_application.png

この状態で、ユーザAがアプリケーション1からログアウトすることを考えます。
ユーザAによるログアウト操作で、アプリケーション1がLogout Endpointをコールしたとしましょう。
call_logout_endpoint.png

すると、ユーザAのトークンが無効になります。このとき問題が発生します。ユーザAは、アプリケーション1のみからログアウトしたつもりが、なぜかアプリケーション2からもログアウトされてしまいます。1回のログアウトですべてのアプリケーションからログアウトできるというのは、SSO用途を考えれば便利な機能ですが、今回のようなユースケースでは、ユーザビリティに課題があります。
logout.png

一方、ユーザAによるログアウト操作で、アプリケーション1がToken Revocation Endpointをコールした場合はどうでしょうか。
call_token_revocation_endpoint.png

この場合は、Token Revocation Endpointコール時にtokenパラメータに指定したトークン、つまりアプリケーション1に払い出されたトークンのみが無効になるため、アプリケーション2からログアウトされることはありません。
revoke.png

以上より、昨今のこのようなユースケースにおいて、このToken Revacationがいかに重要な機能かをお分かりいただけたかと思います。

KeycloakのToken Revocationを使ってみる

Keycloakを用いて、Token Revocationを試してみましょう。Keycloakは2020/11/27時点のmasterブランチのものを使用します。

まずは2つのアプリケーションに同一ユーザでログインします。今回はsample_applicationというアプリケーションとaccount-consoleというアプリケーションにログインしました。
multi_client_sessions.png

まずは、Logout Endpointを叩いてみましょう。

$ curl -i http://keycloak.example.com:8080/auth/realms/
sample_service/protocol/openid-connect/logout -d "refresh_token=$refresh_token&c
lient_id=sample_application&client_secret=***"
HTTP/1.1 204 No Content
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Referrer-Policy: no-referrer
Content-Security-Policy: frame-src 'self'; frame-ancestors 'self'; object-src 'none';
Date: Fri, 04 Dec 2020 01:56:49 GMT
X-Robots-Tag: none
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff

想定通り、セッションが空になり、2つのアプリケーションの両方からログアウトされました。
no_session.png

次に、再度2つのアプリケーションに同一ユーザでログインし、今度はToken Revocation Endpointを叩いてみましょう。ここでは、sample_applicationに発行したトークンを無効にします。

$ curl -i http://keycloak.example.com:8080/auth/realms/sample_service/protocol/openid-connect/revoke -d "token=$refresh_token&client_id
=sample_application&client_secret=***"
HTTP/1.1 200 OK
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Referrer-Policy: no-referrer
Content-Security-Policy: frame-src 'self'; frame-ancestors 'self'; object-src 'none';
Date: Fri, 04 Dec 2020 02:02:30 GMT
Connection: keep-alive
X-Robots-Tag: none
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Content-Length: 0

想定通り、sample_applicationのセッションのみが削除され、account-consoleのセッションが残りました。
revoke_result.png

ちなみに、KeycloakはRFC 8414RFC 8615に準拠したAuthorization Server Metadataを/auth/realms/{realm}/.well-known/openid-configurationというエンドポイントで公開しており、そのエンドポイントからも今回使用した2つのエンドポイントを確認できます。(Authorization Server MetadataへのToken Revocation Endpointの追加も筆者がPR #7106でコミットしました。)

$ curl http://keycloak.example.com:8080/auth/realms/sample_service/.well-known/openid-configuration | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3371  100  3371    0     0   219k      0 --:--:-- --:--:-- --:--:--  235k
{
  ...
  "end_session_endpoint": "http://keycloak.example.com:8080/auth/realms/sample_service/protocol/openid-connect/logout",
  ...
  "revocation_endpoint": "http://keycloak.example.com:8080/auth/realms/sample_service/protocol/openid-connect/revoke",
  "revocation_endpoint_auth_methods_supported": [
    "private_key_jwt",
    "client_secret_basic",
    "client_secret_post",
    "tls_client_auth",
    "client_secret_jwt"
  ],
  "revocation_endpoint_auth_signing_alg_values_supported": [
    "PS384",
    "ES384",
    "RS384",
    "HS256",
    "HS512",
    "ES256",
    "RS256",
    "HS384",
    "ES512",
    "PS256",
    "PS512",
    "RS512"
  ],
  ...
}

おわりに

本稿では、Token Revocationについてご紹介しました。Token Revocationをサポートしたことで、KeycloakはOAuth周りの機能を一通りそろえたとともに、現在はFAPI (Financial-grade API)への対応も絶賛推進中です3。是非この機会にKeycloakを使ってみてはいかがでしょうか。

26
10
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
10