KeycloakのCookieについて

## きっかけ
- [Keycloakの8.0.2でSameSiteの対応が実施されました。](https://www.keycloak.org/2020/02/keycloak-802-released.html)
  - KeycloakのSameSiteの影響については[Jira](https://issues.redhat.com/browse/KEYCLOAK-12125)に記載されています。
- 今回の対応で、` Secure; SameSite=None;  ` がセットされるものとされないものがセットされるようになります。
  - HTTPアクセスなどの場合は末尾に ` _LEGACY ` が付いたCookieが利用されることになります。
- [Keycloakの11.0で `AUTH_SESSION_ID ` にもSameSiteの対応が行われました。](https://issues.redhat.com/browse/KEYCLOAK-13819) ※2020/08/01追記

<img width="882" alt="スクリーンショット 2020-08-01 12.20.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116278/136a5f26-db3b-350a-eb94-5fb551097abb.png">


- Keycloakでも複数のCookieが使われているので、今回良い機会なのでKeycloakのCookieについて調べてみようと思いました。

## Keycloakで利用されるCookie
### AUTH_SESSION_ID
- Keycloakのログイン画面にアクセスすることでセットされるCookieです。
- 未認証→認証済の状態になっても、この値は変わりません。
- ` セッションID.Keycloakノード名 `の形式になります。
  - ` ce31cd04-9eb6-40f2-a276-08221940b24e.65de8f8fb853 `
- Keycloakノード名については ` -Djboss.node.name=ノード名 ` のパラメータで指定可能です。
  - このノード名はスティッキーセッションを実現したい場合にも利用されます。
- またノード名と異なるノードにアクセスがあっても、infinispanがこのCookie内のノード名をもとに他ノードにセッションを検索します。
- オフライントークン発行時もこのセッションIDがkeyとなり、データベースに保存されます。

### KC_RESTART
- クライアントがタイムアウトした際などに、認証セッションを再開するために利用されるCookieです。
- 認証が完了するとブラウザからCookieの値自体は削除されていました。
- JWTフォーマットになっていて、デコードすると以下のようなデータになっています。
- デコードには[jwt.ms](https://jwt.ms/)を使わせてもらいました。

```json
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "6914b91b-e155-4522-b9fe-6d6b6e94cb0a"
}.{
  "cid": "security-admin-console",
  "pty": "openid-connect",
  "ruri": "https://keycloak.example.com/auth/admin/master/console/#/realms",
  "act": "AUTHENTICATE",
  "notes": {
    "scope": "openid",
    "iss": "https://keycloak.example.com/auth/realms/master",
    "response_type": "code",
    "redirect_uri": "https://keycloak.example.com/auth/admin/master/console/#/realms",
    "state": "fbcc5387-1f82-4c22-8376-840168407c17",
    "nonce": "e1bae1d9-8db3-4446-8009-683628eaa1d1",
    "response_mode": "fragment"
  }
}.[Signature]
```

### KEYCLOAK_IDENTITY
- デコードすると以下のようなJWTのフォーマットのデータがセットされています。
- これはOIDCのレスポンスで取得できる ` refresh_token ` と同じ値でした。

```json
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "6914b91b-e155-4522-b9fe-6d6b6e94cb0a"
}.{
  "jti": "5736d6c9-e0c5-450e-b842-579b9cdb61ef",
  "exp": 1581170562,
  "nbf": 0,
  "iat": 1581134562,
  "iss": "https://keycloak.example.com/auth/realms/master",
  "sub": "269495fb-ab25-4ef7-98e3-9d1ade5f5d00",
  "typ": "Serialized-ID",
  "auth_time": 0,
  "session_state": "4698ec24-ad20-4359-8141-921aa932c45a",
  "state_checker": "Q4g3DH2-WDvqhxwAEr5_naVn5gnNmVRD8kWq5tkOM68"
}.[Signature]
```

### KEYCLOAK_IDENTITY_LEGACY
- HTTPアクセスの場合は ` _LEGACY ` 付きのCookieのみがセットされます。

### KEYCLOAK_LOCALE
- Keycloakのアカウント管理の言語表示のために利用されるCookieです。

### KEYCLOAK_SESSION
- ` レルム名/ユーザーID/セッションID `の形式です。
- ` master/e5630f99-cf4f-4615-899f-e5825c1fc182/ce31cd04-9eb6-40f2-a276-08221940b24e `
- セッションIDはAUTH_SESSION_IDの初めの部分と同じになります。

### KEYCLOAK_SESSION_LEGACY
- HTTPアクセスの場合は ` _LEGACY ` 付きのCookieのみがセットされます。
- [KEY_CLOAK_SESSIONがセットされていない場合はこちらのCookieが利用されます。](https://github.com/keycloak/keycloak/blob/master/adapters/oidc/js/src/main/resources/login-status-iframe.html#L82)

## 感想
### スティッキーセッションについて
- AUTH_SESSION_IDでスティッキーセッションを実施しようとするとリバースプロキシやロードバランサーで末尾部分をチェックする必要があります。
- セッションIDと紐づかないノード名のみのCookieがなく、解析等をリバースプロキシやロードバランサーで必要になるので少し面倒かなと思いました。

### Cookie名について
- Cookieの名前についても、Keycloak使ってないように見せることはできないのかな？って思いましたが、[名前についてはハードコードされているよう](https://github.com/keycloak/keycloak/blob/master/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java#L127)で変更はできないように見えました。
- 大手のサイトでKeycloakを使っているサイトもありますが、名前の変更はされていないようでした。
- [OpenAMの場合は iPlanetDiretoryPro からCookie名を変更することが言われている](https://backstage.forgerock.com/docs/openam/13/admin-guide/#avoid-obvious-defaults)ので、デフォルト値からは変更するものだと思ってました。

### AUTH_SESSION_IDについて
- AUTH_SESSION_IDのCookieは ` Secure; SameSite=None;  ` はセットされず、 ` _LEGACY `付きのCookieが新たにセットされているようには見えませんでした。
- KEYCLOAK_SESSIONでセッションIDが送られてくるので、AUTH_SESSION_IDはスティッキーセッションを実現したい場合以外は特に不要なのかもしれません。

### KC_RESTARTについて
- KC_RESTARTが効果を発揮するシーンがいまいちわかりませんでした。時間ができたら、調査しようと思います。



## 参考
- AUTH_SESSION_IDについて
  -  [Keycloak日本語ドキュメント スティッキーセッション](https://keycloak-documentation.openstandia.jp/master/ja_JP/server_installation/index.html#sticky-sessions)
- KC_RESTARTについて
  - [Keycloak日本語ドキュメント Infinispanキャッシュ 認証セッション](https://keycloak-documentation.openstandia.jp/master/ja_JP/server_installation/index.html#cache)