【Keycloak】Admin REST API によるユーザ一覧の取得

## 1. はじめに
Keycloak は、システムにおける認証と認可を管理するためのオープンソースソフトウェアです。Keycloak には、管理者がシステムを操作できる Admin REST API が提供されており、この API を使うことで管理コンソールへアクセスせずに様々な操作ができます。本記事では、この API を用いてユーザ一覧を取得する方法について、具体的な手順を解説します。

### 1-1. この記事でわかること
- Keycloak の Admin REST API を用いてユーザ一覧を取得する方法
- ユーザ一覧の取得に失敗した場合のトラブルシューティング

### 1-2. この記事の対象者
- Keycloak の Admin REST API を用いてユーザ一覧を取得したい人
- 初めて Keycloak の REST API を使用する人
- ユーザ一覧取得に失敗した場合の原因と解決策を探している人

### 1-3. この記事の大まかな流れ
1. 前提条件
2. ユーザ一覧取得の概要
3. ユーザ一覧取得の手順
4. トラブルシューティング

## 2. 前提条件
ユーザ一覧を取得するために必要な環境と事前準備について説明します。

### 2-1. 環境
- Windows 11
- Keycloak 26.0.7
- OpenJDK 21.0.5
- Postman 11.22.0

### 2-2. 事前準備
Keycloak の Admin REST API を使用するためには、まず Keycloak を正しくセットアップする必要があります。次の準備を完了してください。

#### 2-2-1. Keycloak の構築
Keycloak をセットアップするためには、以下の2つのインストールが必要です。

- OpenJDK 21.0.5
- Keycloak 26.0.7

インストール手順については、[こちらの記事](https://qiita.com/sukegoro/items/af3badaf6e6d59f9bc32)を確認してください。

:::note warn
Keycloak の初回起動時には、以下のような環境変数を設定してください。これらの設定が誤っていると、管理コンソールにログインできない可能性があります。

- KEYCLOAK_ADMIN
- KEYCLOAK_ADMIN_PASSWORD

設定に誤りがあった場合には、Keycloak を再インストールしてください。
:::

#### 2-2-2. Postman のインストール
API リクエストをテストするための Postman をインストールし、使用方法を確認してください。インストールについては、[Postman のダウンロードページ](https://www.postman.com/downloads/)を確認してください。

※　Postman の使用方法については[こちらの記事](https://apidog.com/jp/blog/postman-user-manual/)で確認できます。

## 3. ユーザ一覧取得の概要
Admin REST API を用いたユーザ一覧の取得手順を理解するために、本記事で行うユーザ一覧の取得フローの概要を解説します。

### 3-1. ユーザ一覧取得のユースケース
認証・認可サーバのユーザ一覧を取得するユースケースの例を以下に示します。

- Keycloak のユーザイベントログ（ログイン、ログアウトなど）に含まれるユーザ ID と Admin REST API によって作成したユーザ一覧を紐づけることで、ユーザイベントの監査を容易にするバッチ処理を作成する。
- Keycloak に登録されたユーザ情報の一覧を Admin REST API を使用して定期的に取得し、顧客管理システムなどの外部システムに連携することで、外部システムのユーザ一覧を自動的に更新する。これによって、ユーザ情報の更新・追加・削除を手動で行う手間を省き、ユーザ管理の効率化を図る。

これらのユースケースに加えて、その他にもさまざまな利用方法があります。

### 3-2. アクセストークンの取得
REST API を呼び出すには、認可サーバでクライアントが認可された証拠となるアクセストークンが必要です。OAuth 2.0 では、アクセストークンを取得するために4種類のフローが定義されています。今回はユーザ認証が必要ないため、クライアント認証のみを行う**クライアントクレデンシャルズフロー**を使用します。

|フロー  |Keycloak での表記  |ユースケース  |
|---|---|---|
|認可コードフロー  |Standard Flow  |ユーザの認証・認可が必要な場合  |
|インプリシットフロー  |Implicit Flow  |セキュリティ上の理由で非推奨  |
|リソースオーナーパスワードクレデンシャルズフロー  |Direct Access Grants  |セキュリティ上の理由で非推奨  |
|クライアントクレデンシャルズフロー  |Service Accounts  |クライアント認証のみ必要な場合  |

※　OAuth 2.0 については[こちらの記事](https://invisibletechnology.jp/api-oauth-2-0/)で確認できます。

### 3-3. ユーザ一覧取得のフロー
本記事では、以下のようなフローでユーザ一覧を取得します。

1. **トークンリクエスト**
事前に認可サーバが発行したクライアント ID とクライアントシークレットを使用してアクセストークンをリクエストします。認可サーバは、受け取った値が、保存されている値と一致するかを確認してクライアントを認証します。
2. **トークンレスポンス**
クライアントが認証された証拠となるアクセストークンをクライアントに返します。
3. **API の呼び出し**
発行されたアクセストークンを付与して、ユーザ一覧を取得する Admin REST API を呼び出します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/8a867d23-e13d-9693-be9c-0c8fe9eaaad6.png)

## 4. Keycloak の設定
Admin REST API を用いてユーザ一覧を取得する前に必要な Keycloak の設定の手順を説明します。

### 4-1. レルムの作成
ユーザやクライアント、認証方法などを管理するための領域である**レルム**を作成します。

左上の master をクリックし、Create Realm を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/4075b10f-a3c9-229a-4248-392d2eb2877b.png)

**【設定項目】**
- **Resource file**
本記事では**空欄**とします。ここには、レルム設定を JSON 形式で記述したファイルをアップロードすることができ、レルム設定を自動化できます。
- **Realm name**
**任意のレルム名**を入力します。
- **Enable**
デフォルトの **On** とします。ここでは、レルムが有効か無効かを設定できます。

設定後、Create をクリックしてレルムを作成します。

:::note info
Users > Create user から、Admin REST APIで取得対象となるユーザーを複数作成してください。ユーザの作成方法については[こちらの記事](https://www.ipride.co.jp/blog/2284)を確認してください。
:::

### 4-2. クライアントの作成
Keycloak のサービスを利用するアプリケーションである**クライアント**を作成します。

左上に作成したレルム名が表示されていることを確認します。 Clients > Clients list > Create client を開きます。

#### 4-2-1. クライアントの設定

**General settings**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/5d55c4d7-6d53-b9d6-17f7-843494a121dc.png)

**【設定項目】**
- **Client type**
デフォルトの **OpenID Connect** を選択します。ここでは、使用する認証・認可プロトコルを設定します。OpenID Connect か SAML を選択できます。
- **Client ID**
**任意のクライアント識別子**を入力します。
- **Name**
本記事では**未入力**とします。ここでは、クライアントの表示名を設定できます。
- **Description**
本記事では**未入力**とします。ここでは、クライアントの説明を設定できます。
- **Always display in UI**
デフォルトの **Off** とします。ここでは、ユーザのアカウント管理画面にクライアントを常に表示するかどうかを制御します。On の場合にはセッションが維持されていない場合にも表示され、Off の場合にはセッションが維持されている場合にのみ表示されます。

※　OpenID Connect と SAML については[こちら](https://qiita.com/ykna/items/2367fe3cd13460baac9f)で確認できます。

設定後、Next をクリックします。

**Capability config**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/44488ca7-fe2f-11bc-8c2a-fc0b48ea1fe3.png)

**【設定項目】**
- **Client authentication**
**On** に設定します。On の場合はコンフィデンシャルクライアント、Off の場合はパブリッククライアントになります。
- **Authorization**
**On** に設定します。On にするとクライアントに対してさらに細かい認可管理が可能となります。
- **Authentication flow**
本記事では**デフォルト設定**とします。ここでは、クライアントが行う認証フローを選択できます。

※　コンフィデンシャルクライアントとパブリッククライアントについては[こちらの記事](https://zenn.dev/maronn/articles/oauth-public-client-and-confidential-client)で確認できます。
※　認証フロー については[こちらの記事](https://invisibletechnology.jp/api-oauth-2-0/)で確認できます。
※　OAuth 2.0 Device Authorization Grant については[こちらの記事](https://auth.wiki/ja/device-flow)で確認できます。
※　OIDC CIBA Grant については[こちらの記事](https://www.nri-secure.co.jp/blog/openid-connect-ciba-implementation)で確認できます。

設定後、Next をクリックします。

**Login settings**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/a4999e90-48c5-d076-5714-bfe64f3fad64.png)

本記事では、試行レベルの実装なので、このセクションの設定値は**すべて未入力**とします。

**【設定項目】**
- **Root URL**
相対 URL が設定されている場合、その前にここで設定した Root URL が追加されます。
- **Home URL**
ここでは、認証サーバーのリダイレクトや、アプリへ戻る際に使われる URL を設定できます。
- **Valid redirect URIs**
ここでは、ログイン後のリダイレクト先として、有効なパターンを登録できます。
- **Valid post logout redirect URIs**
ここでは、ログアウト後のリダイレクト先として、有効なパターンを登録できます。
- **Web origins**
許可するCORSオリジンを登録します。

※　CORS については[こちらの記事](https://qiita.com/dfdusa/items/0b2da313421fa669a3b9)で確認できます。

設定後、Save をクリックしてクライアントを作成します。

#### 4-2-2. クライアントシークレットの確認
Clients > [作成したクライアント] > Cledentials を開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/fc77bcee-92da-726c-dc27-c386274fd52a.png)

ここでクライアントシークレットの値を確認できます。確認した**Client Secret の値は控えておいてください**。

#### 4-2-3. サービスアカウントロールの設定
クライアントが Keycloak とやり取りするために使用するアカウントである**サービスアカウント**を作成します。サービスアカウントにロールを付与することによって、REST API による Keycloak の操作を許可します。

Clients > [作成したクライアント] > Service accounts roles > Assign role を開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/0eca5c33-e95d-fdd3-81c8-c2c61e8f4356.png)

フィルターで Filter by clients を選択し、view-users で検索します。**view-users** を選択して Assign をクリックし、ロールを割り当てます。view-users ロールは、ユーザを参照する操作を許可するロールです。

:::note warn
サービスアカウントロールを誤って設定すると、Admin REST API を実行できない可能性があります。詳しくは「6. ユーザ一覧取得に失敗するトラブル」で解説します。
:::

:::note info
- realm-admin ロールを付与すると、すべての Admin REST API を実行できるようになりますが、セキュリティ上のリスクが高く、最小権限の原則から推奨されません。
- Admin REST API を実行するためには、その API に必要なロールをサービスアカウントに割り当てることで、API を利用できるようになります。
:::

## 5. Admin REST API によるユーザ一覧の取得
Keycloak の Admin REST API を用いてユーザ一覧を取得する手順を解説します。他の Admin REST API については[公式ドキュメント](https://www.keycloak.org/docs-api/latest/rest-api/index.html)で確認できます。

### 5-1. トークンリクエスト
Admin REST API を呼び出すために必要な、認可サーバでクライアントが認可された証拠となるアクセストークンを取得します。

Postman を使ってリクエストを送信します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/28527c51-c128-9193-8d6d-f1609d50e648.png)

**【設定項目】**

- **メソッド**：POST
-  **URL**：http://localhost:8080/realms/test-realm/protocol/openid-connect/token
-  **Body**：x-www-form-urlebcoded
    -  grant_type：client_credentials
    -  client_id：test-client
    -  client_secret：控えたクライアントシークレット

Body に設定する grant_type は認可フローの設定です。本記事ではクライアントクレデンシャルズフローを使用するため、client_credentials を指定します。

### 5-2. トークンレスポンス
トークンリクエストに対するレスポンスの内容について説明します。

**【レスポンス内容】**

```json
{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIySEc5c...",
    "expires_in": 300,
    "refresh_expires_in": 0,
    "token_type": "Bearer",
    "not-before-policy": 0,
    "scope": "profile email"
}
```
- **access_token**
認可サーバでクライアントが認可された証拠となるアクセストークンです。
- **expires_in**
アクセストークンが有効な時間を示します。ここでは 300 秒（5分）と記載されています。
- **refresh_expires_in**
リフレッシュトークンの有効期限です。今回は 0 となっており、リフレッシュトークンは発行されないことを意味します。クライアントクレデンシャルズフローでは、リフレッシュトークンは使用されません。
- **token_type**
アクセストークンの種類を示します。今回は、Bearer トークンとなっています。
- **not-before-policy**
アクセストークンが有効になる時間を示しています。ここでは 0 とあり、発行された直後からアクセストークンを使用できることを意味します。
- **scope**
アクセストークンでアクセス可能な範囲（権限）を示します。ここでは「profile」と「email」が指定されており、アクセストークンを使ってユーザーのプロフィール情報やメールアドレス情報にアクセスすることができます。

ここで取得した**アクセストークンは控えておいてください**。

### 5-3. API の呼び出し
取得したアクセストークンを使用して、ユーザ一覧を取得する Admin REST API を実行します。

Postman を使ってリクエストを送信します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/77a7dcba-c79d-1f94-3e8c-052c1011c506.png)

**【設定項目】**

- **メソッド**：GET
- **URL**：http://localhost:8080/admin/realms/test-realm/users
- **Authorization**
    - type：Bearer Token
    - Token：控えたアクセストークン

Authorization の type はアクセストークンの種類を指します。今回の場合、アクセストークンを取得する際のレスポンスで、Bearer トークンが指定されているため Bearer Token を選択します。

**【レスポンス内容】**
```json
[
    {
        "id": "865df5bd-5c81-4228-8a95-658d1ad3605e",
        "username": "user1",
        "firstName": "first_name_user1",
        "lastName": "last_name_user1",
        "emailVerified": false,
        "createdTimestamp": 1734514744934,
        "enabled": true,
        "totp": false,
        "disableableCredentialTypes": [],
        "requiredActions": [],
        "notBefore": 0,
        "access": {
            "manageGroupMembership": false,
            "view": true,
            "mapRoles": false,
            "impersonate": false,
            "manage": false
        }
    },
    {
        "id": "2bdacec7-ac9f-4f1e-a59e-109d0e3a2793",
        "username": "user2",
        "firstName": "first_name_user2",
        "lastName": "last_name_user2",
        "emailVerified": false,
        "createdTimestamp": 1734514830719,
        "enabled": true,
        "totp": false,
        "disableableCredentialTypes": [],
        "requiredActions": [],
        "notBefore": 0,
        "access": {
            "manageGroupMembership": false,
            "view": true,
            "mapRoles": false,
            "impersonate": false,
            "manage": false
        }
    }
]
```
項目が多いため一部のみ説明します。

- **emailVerified**
ユーザーのメールアドレスが確認済みかどうかを示します。false の場合はまだ確認されていません。
- **createdTimestamp**
ユーザーアカウントが作成された日時を示すタイムスタンプです。
- **enabled**
ユーザーアカウントが現在有効かどうかを示します。true の場合はアカウントが有効です。
- **totp**
ユーザーが TOTP（Time-based One-Time Password）という二要素認証を使用しているかどうかを示します。false は使用していないことを意味します。
- **disableableCredentialTypes**
ユーザーの無効化可能な認証方法（例：パスワード認証）のリストです。空の場合は無効化できる認証方法がありません。
- **requiredActions**
ユーザーアカウントを有効にするための必要なアクション（例：メール認証）を示します。このリストが空であれば、追加のアクションは必要ありません。
- **notBefore**
トークンが有効になる最初の時間を示します。0 の場合、直ちに利用可能です。
- **access**
    - manageGroupMembership
    ユーザーがグループメンバーシップを管理できるかどうかを示します。false の場合は管理できません。
    - view
    ユーザーがリソースを閲覧できるかどうかを示します。true の場合は閲覧可能です。
    - mapRoles
    ユーザーがロールをマッピングできるかどうかを示します。false の場合はできません。
    - impersonate
    ユーザーが他のユーザーになりすまして操作を行えるかどうかを示します。false の場合はできません。
    - manage
    ユーザーがリソースを管理できるかどうかを示します。false の場合は管理できません。

## 6. ユーザ一覧取得に失敗するトラブル
ユーザ一覧の取得に失敗するトラブルの原因と解決方法を説明します。

### 6-1. エラー："error": "HTTP 403 Forbidden"が表示される
**【エラー内容】**
ユーザ一覧を取得するためのリクエストを送信した際に、以下のようなレスポンスが返ってくる。
```json
{
    "error": "HTTP 403 Forbidden"
}
```
**【原因】**
ユーザ一覧を取得する Admin REST API を実行する権限が無いためです。

**【解決策】**
ユーザの参照を可能にする **view-user ロールをサービスアカウントに付与**します。

## 7. おわりに
本記事では、Keycloak の Admin REST API を用いてユーザ一覧を取得する方法について説明しました。ユーザ一覧を取得するまでの全体の流れを理解していただけたら幸いです。今後は、他の API の実行にもぜひ挑戦してみてください。


## 8. 参考資料
- [WindowsでKeycloakをつかう](https://qiita.com/sukegoro/items/af3badaf6e6d59f9bc32)
- [初心者向け：Postmanの基本的な使い方を](https://apidog.com/jp/blog/postman-user-manual/)
- [API認証 OAuth 2.0とは？ 承認フローの種類と適用シーンの解説](https://invisibletechnology.jp/api-oauth-2-0/)
- [Keycloak Admin REST API](https://www.keycloak.org/docs-api/latest/rest-api/index.html)
- [OAuth、OpenID Connect、SAMLとその違いについて大雑把にまとめると](https://qiita.com/ykna/items/2367fe3cd13460baac9f)
- [OAuthにおけるPublic ClientとConfidential Clientについて](https://zenn.dev/maronn/articles/oauth-public-client-and-confidential-client)
- [デバイスフロー (Device flow) とは？](https://auth.wiki/ja/device-flow)
- [OpenID Connect CIBA 実装の具体例と考慮すべきポイント](https://www.nri-secure.co.jp/blog/openid-connect-ciba-implementation)
- [今度こそクロスオリジンとCORSを完全に理解する](https://qiita.com/dfdusa/items/0b2da313421fa669a3b9)
- [Keycloakの管理コンソール画面をみてみる（管理者向けコンソール編）](https://qiita.com/y_yamash/items/8644c8dd97c6f4b50896)
- [KeycloakのAPIでユーザー登録からアクセストークン取得までやってみる](https://qiita.com/takahiro_fukushima/items/9dbb0d001028905fc255)