KeycloakのAPIでユーザー登録からアクセストークン取得までやってみる

## 概要
2023年アドベントカレンダーへ2回目の投稿です。
カレンダーに空きがあり、所属している会社の「いいね」の合計の足しになればと思い、```Keycloak```について投稿してみました。
なぜ```Keycloak```かというと、認証・認可系の情報を読んでいると```Keycloak```の名前がよく出てきていて、アップデートも頻繁にあることから、そろそろ業務でも使われそうな気がするので、このテーマにしました。
現状、```Keycloak```の記事は仕様や技術面など説明が多いので、この記事ではハンズオン形式で、とりあえず動かそうという感じです。
認証・認可は難しいので、広い心で読んでもらえるとありがたいです:bow_tone1:

## Keycloakとは？
```Keycloak```とは、ID管理やアクセス管理のオープンソースソフトウェアで、認証認可サーバとして使うことができます。
同じようなサービスとしてAuth0やAmazon Cognitoがありますが、```Keycloak```はOSSですので費用の発生がなくコストパフォーマンスに期待でき、より柔軟なカスタマイズが可能ですが、冗長構成など非機能要件への対応や管理面は考慮が必要そうです。

詳細は、下記リンク先の公式ページを参考にして下さい。
https://www.keycloak.org/

## ハンズオン
### 目標
この記事を実践すると下記の項目ができるようになります。
* Keycloakの起動
* KeycloakのAPIでユーザー登録
* KeycloakのAPIでユーザーのアクセストークンの取得

ざっくりとユーザー登録と認証までという感じです。

### 前提
* コンテナ実行環境（今回はDocker）は構築済み
* APIテスター（今回はPostman）の使い方は問題ないこと

今回はコンテナ上でKeycloakを起動させますが、
Javaの実行環境が整っていればローカルでも起動できますので、
できそうなところで試してください。

あと設定などセキュリティ等へ考慮はしていませんので、
プロジェクトに導入する際は、その辺の対応はお願いいたします。

### 実践
#### 1. Keycloakの起動
1. ```docker-compose.yml```ファイルを作成し、下記を記載する
   ```yml
   version: '3'
   services:
     keycloak:
       image: quay.io/keycloak/keycloak
       container_name: keycloak
       tty: true
       stdin_open: true
       ports:
         - "8080:8080"
       volumes:
         - ./data/keycloak:/opt/keycloak/data
       environment:
         KEYCLOAK_ADMIN: admin
         KEYCLOAK_ADMIN_PASSWORD: password
       command:
         - start-dev
   ```
1. ```docker-compose up -d --build```コマンドでコンテナを起動させます
1. ブラウザで```http://localhost:8080```に移動し、下図と同じ表示か確認します
![スクリーンショット 2023-12-03 1.37.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/5c3475f5-4b95-71b1-3dd6-555a31248264.png)
<br>これで```Keycloak```が起動しました。
ちなみにDBは、デフォルトで```H2 Database```ですので、フレームワークは```Spring Boot```かなと。```docker-compose.yml```の```volumes```のマウント先は、```H2 Database```のファイルですので、保存した内容を確認できます。

#### 2. Realmの作成
1. 上図の```Administration Console```を押下すると下図のログイン画面に遷移するので、```docker-compose.yml```にて```KEYCLOAK_ADMIN```の値をUsernameに、```KEYCLOAK_ADMIN_PASSWORD```の値をPasswordに入力してサインインを押下する
![スクリーンショット 2023-12-03 6.05.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/aca7843d-3625-b099-c396-c728598d81ed.png)

1. サイドバーの「master」から「create reaml」ボタンを押下し、Reamlの登録ページに遷移する
![スクリーンショット 2023-12-03 6.14.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/5b4abb32-c2ca-512b-b014-03704bb37078.png)

1. Reamlの名前に「test-reaml」と入力し、「Create」を押下する
![スクリーンショット 2023-12-03 6.19.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/4c76407d-fb7c-74ed-733f-06635570849e.png)

これでReamlが作成されます。
そもそもReamlとは、「部門」のような意味でReaml毎にユーザーやロールを管理しています。

#### 3. Clientsの作成
1. サイドバーの「Clients」からClients一覧画面に遷移し、「Create Client」ボタンを押下し、「Create Client」画面に遷移する
![スクリーンショット 2023-12-03 6.37.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/13060a77-4d2e-e918-409f-c49c74ccf420.png)

1. 「Client ID」の値に「test-client」を入力し、「Next」を押下する
![スクリーンショット 2023-12-03 6.42.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/2e863e3d-203d-1d25-bae0-21682351445d.png)

1. 「Client authentication」と「Authorization」をONにし、下図の設定であることを確認し、「Next」を押下する
![スクリーンショット 2023-12-03 6.45.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/76461c3c-4c9d-beea-8edc-165a3c4865f0.png)

1. 今回は試行レベルなので、下図のように特に値を入力せず「Save」を押下し、一覧に「test-client」が作成されていることを確認する
![スクリーンショット 2023-12-03 6.48.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/c7b45733-d3b8-f2be-6288-8b92152a128b.png)

1. 「test-client」の詳細にて「Credentials」ページ内の「Client Secret」の値を控えておく（リクエスト時に必要なので）
![スクリーンショット 2023-12-03 6.53.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/c38bb0ea-1486-75c1-9961-9fe8bc8d7ec7.png)

そもそも、「Client」とは、公式ドキュメントに
> Keycloakにユーザーの認証を要求できるエンティティーです。

と記載されていますが、、、ざっくりとしていて分かりにくい。認証時に必要な設定をあれこれできるところかなと思っています（違っていたら教えてください:bow_tone1:）

#### 3. ユーザー登録（Postman使用）
1. 　下図を参考に、下記設定のリクエストでアクセストークンを取得し、その値を控えておく
* メソッド： POST
* URL： http://localhost:8080/realms/test-realm/protocol/openid-connect/token
* x-www-form-urlebcoded
    * grant_type： client_credentials
    * client_id： test-client
    * client_secret： 上記で控えた値

![スクリーンショット 2023-12-03 7.06.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/d790a804-0fbb-145b-ba7b-f03756a053b3.png)
2. 下記設定のリクエストでユーザーを登録し、Usersにて「test-user」の存在を確認する

![スクリーンショット 2023-12-03 7.21.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/97fd4edd-1e07-518c-b657-b173f55de284.png)

* Authorization
    * Type: Bearer Token
    * Token： 上記で控えたアクセストークン
* メソッド： POST
* URL： http://localhost:8080/admin/realms/test-reaml/users
* Body
    * raw
```json
{
    "credentials": [
        {
            "temporary": false,
            "type": "password",
            "value": "test-password"
        }
    ],
    "username": "test-user",
    "firstName": "test",
    "lastName": "user",
    "email": "test-user@test.com",
    "emailVerified": false,
    "enabled": true
}
```
![スクリーンショット 2023-12-03 7.25.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/c3b4b32e-7263-b73d-bc86-0aae515967a1.png)

とりあえずユーザーの登録はできていますね〜

#### ４. 登録したユーザーのアクセストークンを取得（Postman使用）
1. 下図を参考に、下記設定のリクエストでアクセストークンを取得する

* メソッド： POST
* URL： http://localhost:8080/realms/test-realm/protocol/openid-connect/token
* x-www-form-urlebcoded
    * grant_type： client_credentials
    * client_id： test-client
    * client_secret： 上記で控えた値
    * username： test-user
    * password： test-password

![スクリーンショット 2023-12-03 7.32.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321920/4be806a0-5c16-a331-0946-2451ec6c2464.png)

アクセストークンを取得できていますね。
とりあえず、こんな感じかなと。

## 最後に
まだまだ```Keycloak```についての情報は少なく、「なぜ」に対しての追求がまだまだできていませんが、この記事では「リクエストを投げたら値がちゃんと返ってきた〜」という風に楽しんでもらえればなぁと思います。

それにしても認証認可は本当に難しい、、、実務で認証認可の実装をしたことがありますが、ライブラリやフレームワークに頼っている箇所が多く、「本当に仕組みを理解しているか」と言われると全然です。バリエーションも多く進化も早いので、置いていかれないように頑張って勉強ですね。

この記事についてご指摘がありましたら、コメントにてお願いいたします:bow_tone1: