KeycloakとGo言語でAuthorization Code Flowを学ぶ 4
はじめに
これまで 3回にわたり、Keycloak と Go 言語で Authorization Code Flow を学びました。
- KeycloakとGo言語でAuthorization Code Flowを学ぶ
- KeycloakとGo言語でAuthorization Code Flowを学ぶ 2
- KeycloakとGo言語でAuthorization Code Flowを学ぶ 3
今までログアウトについては触れていなかったため、この記事ではログアウトのエンドポイントにリクエストしてセッションを削除する方法を学びます。
成果物
https://github.com/kntks/blog-code/2024/04/keycloak-authorization-code-flow-4
目標
- API サーバーからログアウトのエンドポイントにリクエストしてセッションを削除する
- Cookie に保存されたアクセストークン、リフレッシュトークン、ID トークンを削除する
環境
バージョン | |
---|---|
Mac | Ventura 13.2.1 |
Keycloak | 23.0.6 |
Docker | 26.0.0 |
Docker Compose | v2.24.5 |
Terraform | 1.7.4 |
Go | 1.22.0 |
Terraform と Docker でセットアップ
Keycloak を docker compose で起動します。
Terraform を使用するために Keycloak側のセットアップ が必要です。
terraform apply で Keycloak の設定を行います。
ログアウトのエンドポイント
Keycloak では、ログアウトのためのエンドポイントが用意されており、今回使用する URL は http://localhost:8080/realms/myrealm/protocol/openid-connect/logout
です。
エンドポイントを調べるには /realms/{realm-name}/.well-known/openid-configuration
のレスポンスにある end_session_endpoint
を確認します。
ログアウトの実装
このエンドポイントに関して、Keycloak のドキュメントには2つの方法が記載されています。
1つ目はリダイレクトする方法です。
The user agent can be redirected to the endpoint, which causes the active user session to be logged out. The user agent is then redirected back to the application.
訳)ユーザエージェントはエンドポイントにリダイレクトされ、アクティブなユーザセッションはログアウトされます。その後、ユーザエージェントはアプリケーションにリダイレクトされます。
2つ目はエンドポイントに直接リクエストを送信する方法です。
The endpoint can also be invoked directly by the application. To invoke this endpoint directly, the refresh token needs to be included as well as the credentials required to authenticate the client.
訳)このエンドポイントは、アプリケーションから直接呼び出すこともできます。このエンドポイントを直接呼び出すには、クライアントを認証するために必要な認証情報だけでなく、リフレッシュトークンを含める必要があります。
引用:2.1.1. Endpoints - Keycloack Documentation
RP-Initiated Logout
1つ目のリダイレクトする方法は、以下の引用を参照すると、RP-Initiated Logout のことを指していることがわかります。
This URL is normally obtained via the end_session_endpoint element of the OP’s Discovery response
訳)このURLは通常、OP の Discovery レスポンスの end_session_endpoint 要素を介して取得されます。
引用:2. RP-Initiated Logout - OpenID Connect RP-Initiated Logout 1.0
You can optionally include parameters such as id_token_hint, post_logout_redirect_uri, client_id and others as described in the OpenID Connect RP-Initiated Logout.
訳)オプションで、OpenID Connect RP-Initiated Logoutで説明されているid_token_hint、post_logout_redirect_uri、client_idなどのパラメータを含めることができます。
Go 言語で実装する前に Keycloak にログアウト後のリダイレクト先を設定します。
左のナビゲーションペインから Clients
を選択し、myclient
を選択します。Settings
タブから Valid post logout redirect URIs
にログアウト後にリダイレクトする URL を設定します。今回は、http://localhost:8081/login
を設定します。
Terraform の設定も変更します。
このセクションでは、Go 言語で実装した REST API に /logout
エンドポイントは作成し RP-Initiated Logout を実装します。
必要なパラメータは以下の通りです。
- id_token_hint
- RECOMMENDED
- ログアウトするユーザの ID トークン
- logout_hint
- OPTIONAL
- client_id
- OPTIONAL
- ログアウトするクライアントの ID
- post_logout_redirect_uri
- OPTIONAL
- ログアウト後にリダイレクトする URL
- state
- OPTIONAL
- CSRF 対策のためのランダムな文字列
- ui_locales
- OPTIONAL
API サーバーを起動します。
実際に Keycloak の Session を確認しながらログアウトを実行すると、ログアウト後にリダイレクトされ、Session も削除されていることが確認できました。
クエリパラーメータは、client_id
や id_token_hint
のみでもログアウトは可能です。そのような設定の場合、ログアウト後に Keycloak は以下の画面になります。
クエリパラメータが、post_logout_redirect_uri
と client_id
のみの場合、ログアウト後に確認ページが表示されます。
直接リクエストを送信するログアウト
POST リクエストに必要なパラメータは以下の通りです。
- client_id
- client_secret
- refresh_token
参考:https://stackoverflow.com/a/77135305
POST リクエストに成功すると、Keycloak は 204 No Content を返すことがわかりました。そのため、以下のように実装します。
API サーバーを起動します。
ログイン後に Web ブラウザから http://localhost:8081/logout2
にアクセスすると、ログイン画面にリダイレクトされることが確認できました。
Cookie の値を削除する
ログアウトの実装をしたことで問題点が出てきました。
それは、ログアウト後に再度 /home
にアクセスすると、リクエストが成功してしまうことです。
これは、Cookie が削除されていないことが原因です。
API サーバーから Cookie を削除するには、Cookie の有効期限を過去に設定します。
to remove a cookie, the server returns a Set-Cookie header with an expiration date in the past. The server will be successful in removing the cookie only if the Path and the Domain attribute in the Set-Cookie header match the values used when the cookie was created.
訳)クッキーを削除するには、サーバーが過去の有効期限を設定したSet-Cookieヘッダーを返します。サーバーがクッキーを正常に削除できるのは、Set-CookieヘッダーのPathとDomainの属性値が、クッキーが作成された時に使用された値と一致する場合のみです。
参考:Correct way to delete cookies server-side - stack overflow
ログアウトの実装に Cookie の削除を追加します。
API サーバーを起動します。
実際に API サーバーを起動して /logout
にアクセスした後に Cookie が削除されることを確認しました。
まとめ
Keycloak にはログアウトする方法が2つあることがわかりました。そしてログアウトのエンドポイントにリクエストすることで Keycloak のセッションを削除する方法を学びました。また、Cookie の削除方法についても学びました。
さいごに
2024年2月ごろから OpenID Connect と Keycloak を学びながら、Go 言語で API サーバーを作成してきました。楽をするためにアクセストークンを Cookie に保存する実装をしましたが、実際のアプリケーションでは、Redis などの永続ストレージに保存することをオススメします。
そのほかにも、Token Revocation や Token Introspection など、触れていない仕様がたくさんありますし、Keycloak 自体の設定もほとんど触れていません。
この “Authorization Code Flow を学ぶ” シリーズはこれで終わりにしますが、今後も OpenID Connect や Keycloak について学びながら、新しい記事を書いていきたいと思います。