KeycloakとGo言語でAuthorization Code Flowを学ぶ 3
はじめに
前々回の記事では Authorization Code Flow について調べながら、Go 言語で API サーバーを作成しました。前回では、state や nonce、PKCE について調べながら、セキュリティを考慮したコードを書いていきました。前回の実装は、https://github.com/kntks/blog-code/2024/03/keycloak-authorization-code-flow-2/sample にあります。
しかし、この API サーバーにはまだ問題があります。それは、アクセストークンの有効期限が切れた場合、再度ログイン画面にアクセスしないといけないことです。
この記事では、リフレッシュトークンを使うことで、アクセストークンを再取得する方法を学びます。
成果物
https://github.com/kntks/blog-code/2024/04/keycloak-authorization-code-flow-3
目標
- アクセストークンの有効期限が切れても、リフレッシュトークンを使ってアクセストークンを取得できるようにする
- リフレッシュトークンが切れた場合は、再度ログイン画面にリダイレクトさせる
環境
バージョン | |
---|---|
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 の設定を行います。
リフレッシュトークンとは
リフレッシュトークンはアクセストークンを再発行するために使用されるクレデンシャルです。アクセストークン、ID トークンと一緒に発行され、主に、現在のアクセストークンが無効化されたり、アクセストークンの期限が切れた際に新しいアクセストークンを取得するために使用されます。
リフレッシュトークンを使ってアクセストークンを取得するには、Token Endpoint にリクエストを送信します。
Keycloak の Token Endpoint は /realms/{realm-name}/protocol/openid-connect/token
です。
前々回の記事ではアクセストークン、ID トークンを取得するためにリクエストに以下のパラメータを含めました。
- grant_type
- 値は “authorization_code”
- code
- Authorization Code Flow で取得したコード
- redirect_uri
- client_id
- client_secret
- code_verifier
参考:4.1.3. アクセストークンリクエスト - RFC6749
しかし、リフレッシュトークンを使ってアクセストークンを取得する場合は、以下のパラメータを含めます。
- grant_type
- 値は “refresh_token”
- refresh_token
- scope
- 設定は任意
- client_id
- client_secret
参考:
有効期限を変更する
Keycloak では、Realm settings
ページから SSO Session Idle
の値を変更することで、リフレッシュトークンの有効期限を設定できます。
デフォルトの有効期限は 30 分です。
Keycloak では、Token Endpoint のレスポンスにリフレッシュトークンの有効期限(refresh_expires_in)が含まれるので、設定が反映されているか確認できます。
以下は SSO Session Idle
を 20 分に設定した場合のレスポンスです。
どこに保存するのか
リフレッシュトークンはアクセストークンを比べて期限が長いため、Cookie などのフロントエンド側のストレージに保存するよりも、サーバーサイドの永続ストレージに保存する方が安全です。
Refresh tokens need to be long-lived and revocable, so they need to be stored in persistent storage server-side.
訳)リフレッシュ・トークンは長寿命で取り消し可能である必要があるため、サーバー側の永続ストレージに格納する必要がある。
しかし、SPA などのフロントエンドアプリケーションの場合、リフレッシュトークンをサーバーサイドに保存することは難しいため、Cookie などのフロントエンド側のストレージに保存することもあるそうです。
参考:Simple and Secure API Authentication for SPAs - medium
トークンをリフレッシュできるようにする
まずアクセストークン、リフレッシュトークンの状態の組み合わせを考えます。
アクセストークン | リフレッシュトークン | APIの挙動 |
---|---|---|
✅ 期限内 | ✅ 期限内 | アクセスを許可 |
✅ 期限内 | ❌ 期限切れ | アクセスを許可 |
❌ 期限切れ | ✅ 期限内 | 新規にアクセストークンを発行する |
❌ 期限切れ | ❌ 期限切れ | ログイン画面にリダイレクトする |
前回の記事で書いたサンプルコードをベースに、リフレッシュトークンを使ってアクセストークンを取得するコードを書いていきます。
エラーがあった場合は、認可に失敗したとしてログイン画面にリダイレクトします。
アクセストークンが期限切れの場合、リフレッシュトークンを使ってアクセストークンを更新する関数を追加します。
Keycloak の設定からアクセストークンとリフレッシュトークンの有効期限を個別に短く設定したり、両方とも短く設定することで期限切れの状態を再現し、動作確認を行いました。
実際にリフレッシュトークンを使ってアクセストークンを取得すると以下のようなレスポンスが返ってきます。
アクセストークンとリフレッシュトークンどちらも期限切れの状態でリクエストを送信すると、以下のようなエラーレスポンスが返ってきます。
さいごに
これで、リフレッシュトークンが有効であれば、アクセストークンの有効期限が切れても再取得できるようになりました。次回はログアウトの機能を追加します。