Keycloakを自社の会員DBや人事システムとつなぐとき、管理コンソールの画面操作を自動化する入口になるのがAdmin REST APIです。本記事では、2026年11月5日時点の最新版Keycloak 26.8.1を前提に、サービスアカウントを持つクライアントの作り方、必要な管理ロールの選び方、client_credentialsでのトークン取得、ユーザーの作成・検索・ロール付与・無効化までを、そのまま動かせるcurlのコマンド例で解説します。つまずきやすい401・403・409の切り分けと、APIで連携を自作すべきかの判断基準も扱います。
まとめ:Keycloak APIはサービスアカウントのトークンで管理APIを呼ぶ
Keycloakの管理操作は、/admin/realms/{realm}配下のAdmin REST APIで呼べます。管理コンソールでできる操作はすべてAPIにもあり、2026年11月時点の公式OpenAPI定義には274のパスが載っています。
アプリから呼ぶなら、管理者のパスワードではなく、サービスアカウントを有効にしたクライアントのトークンを使います。ロールは対象レルムのrealm-managementから、必要なものだけを渡す設計です。ユーザーの作成・検索・更新はmanage-usersで足ります。ロールを名前で引く処理を入れるならview-realmも要ります。
数百人規模までの会員同期や入退社の反映なら、APIを直接呼ぶ実装で十分に回ります。既存のLDAPやActive Directoryが正本なら、APIで同期を書くよりUser Federationで読み込む構成を先に検討してください。
Keycloak APIの全体像:認証用OIDCとAdmin REST APIの役割分担
「Keycloak API」と呼ばれるものは、パスの先頭で2系統に分かれます。どちらを呼ぶのかを先に決めないと、トークンの取り方もロール設計も定まりません。製品そのものの機能や他製品との違いはKeycloakとは?Oktaとの違いと連携手順で扱っています。
/realms配下のトークン発行と/admin/realms配下の管理操作の違い
/realms/{realm}/protocol/openid-connect/配下は、ログインやトークン発行を担う標準のエンドポイントに当たります。アプリの利用者が認証するときに使い、仕様はOAuth 2.0とOpenID Connectに従います。
/admin/realms/{realm}/配下はKeycloak独自の管理APIです。公式のServer Developer Guideは、管理コンソールが持つ機能をすべて備えると説明しています。ユーザーやロールを登録・変更するのはこちらで、呼ぶには管理ロールを持つアクセストークンが要ります。
| 系統 | パスの例 | 主な用途 | 必要な権限 |
|---|---|---|---|
| OIDCエンドポイント | myappのトークン発行用パス | ログイン・トークン発行 | クライアントの資格情報 |
| Admin REST API | myappのユーザー管理用パス | ユーザー・ロール・クライアントの管理 | realm-managementのロール |
表のパス例は、OIDC側が/realms/myapp/protocol/openid-connect/token、管理API側が/admin/realms/myapp/usersです。本記事が扱うのは後者です。トークンは前者で取り、後者にBearerとして渡す、という順に動きます。
公式リファレンス26.8.1で確認できるエンドポイントの探し方
エンドポイントの正本はKeycloak Admin REST APIのリファレンスです。同じ場所にopenapi.jsonがあり、2026年11月5日に取得した定義には274のパスがありました。リファレンスのHTMLは長いので、OpenAPI定義をjqで引くほうが速く探せます。
読むときの注意が2つあります。パスの{client-id}はクライアントの内部ID(UUID)で、画面で入力するclientIdではありません。ロール関連の{role-name}は名前で、IDではありません。リファレンスにも「not clientId!」「not id!」と明記されており、取り違えると404になります。
管理APIを呼ぶトークンの取得:admin-cliとサービスアカウントの使い分け
トークンの取り方は、手元で試す場合とアプリに組み込む場合で分けます。結論から言うと、アプリには管理者のパスワードを持たせず、レルムごとのサービスアカウントを使います。
admin-cliとパスワードグラントで試す方法と有効期限1分の制約
公式ガイドの最初の例は、masterレルムの管理者でadmin-cliクライアントからパスワードグラントでトークンを取る方法です。ガイドには、このトークンは既定で1分で切れると書かれています。
動作確認には手軽です。ただし管理者のパスワードをスクリプトに書くことになり、そのトークンは全レルムを操作できます。バッチや本番のアプリに持ち込む方法ではありません。手元で数回叩いて挙動を見る用途に限ってください。
サービスアカウントを有効にしたクライアントをmyappレルムに作る設定
アプリ用には、管理したいレルム(以下myapp)にAPI専用のクライアントを作ります。管理ガイドのUsing a service accountに沿った手順は次のとおりです。
- 管理コンソールで
myappレルムを選び、Clientsからuser-syncという名前のOpenID Connectクライアントを作る - SettingsでClient authenticationをOnにし、Service account rolesにチェックを入れる。Standard flowはオフにする
- CredentialsタブでClient Secretを控える
- Client scopesタブで専用スコープ(
user-sync-dedicated)を開き、Scopeタブで必要なロールのスコープを割り当てる - Service account rolesタブで、
realm-managementの必要なロールを割り当てる
手順4と5は両方必要です。トークンに入るロールは、スコープの割り当てとサービスアカウントのロールの交差になるからです。26.8系の管理ガイドは「Full Scope Allowed」を非推奨とし、オンにせず必要なスコープを明示するよう求めています。
manage-usersとview-realmに絞るユーザー連携用のロール設計
各レルムにはrealm-managementという組み込みクライアントがあり、管理権限はそのクライアントロールで表されます。管理ガイドのDedicated realm admin consolesには、manage-usersやview-realm、全権を束ねたrealm-adminを含む22個が並びます。
ユーザー連携に要るのは2つです。manage-usersがあればユーザーの作成・検索・更新・削除が通ります。ソースのUserPermissionsは、manage-usersかview-usersを持てば閲覧可、閲覧できれば検索も可と判定しています。
見落としやすいのはロールの参照です。GET /roles/{role-name}は、26.8.1のRealmPermissionsでview-realmかmanage-realmを要求します。manage-usersだけでは403になるため、view-realmの追加が必要です。realm-adminを丸ごと渡すと、漏れたときにレルム設定まで書き換えられます。
client_credentialsでアクセストークンを取得するcurlコマンド
トークンはmyappレルムのトークンエンドポイントへgrant_type=client_credentialsで取りに行きます。管理ガイドのとおり、資格情報はBasic認証のヘッダで送れます。以降の例はjqがある前提です。
KC=http://localhost:8080
REALM=myapp
CLIENT_ID=user-sync
CLIENT_SECRET='CredentialsタブのClient Secret'
TOKEN=$(curl -s -u "${CLIENT_ID}:${CLIENT_SECRET}" \
-d grant_type=client_credentials \
"${KC}/realms/${REALM}/protocol/openid-connect/token" | jq -r .access_token)
echo "${TOKEN}" | cut -c1-20
応答のexpires_inが有効秒数です。この有効秒数を決める設定は、レルムのAccess Token Lifespanです。このグラントではリフレッシュトークンが既定で発行されないため、切れたら同じ要求で取り直します。トークンの中身はJWTの構造どおりで、resource_access.realm-management.rolesに割り当てたロールが入っているかで設定を確かめられます。
Admin REST APIでのユーザー操作:作成・検索・ロール付与・無効化のcurl例
ここからは取得したTOKENを使い、入社から退職までの一連の操作を順に呼びます。myappレルムにapp-userというレルムロールがある前提です。
POST /usersで初期パスワード付きのユーザーを作成する手順
ユーザーの作成はPOST /admin/realms/{realm}/usersです。credentialsにtemporary: trueのパスワードを入れると、初回ログインで変更を求められます。メールアドレスは環境変数NEW_USER_EMAILに入れてから実行してください。
BODY=$(jq -n --arg email "${NEW_USER_EMAIL}" '{
username: "taro.yamada",
email: $email,
firstName: "Taro",
lastName: "Yamada",
enabled: true,
emailVerified: false,
credentials: [{type: "password", value: "Temp-Pass-2026", temporary: true}]
}')
curl -s -i -X POST "${KC}/admin/realms/${REALM}/users" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "${BODY}" | grep -i -E '^(HTTP|location)'
成功すると201が返り、本文は空です。作成したユーザーのIDはLocationヘッダの末尾に入ります。26.8.1のUsersResourceは、作成後にResponse.createdでユーザーIDつきのURLを返しています。
usernameとexact=trueで1件に絞る検索と既定100件のページング
IDが分からないときは検索で引きます。usernameは既定で部分一致なので、exact=trueを付けないとtaroでtaro.yamadaもtaro2も返ります。
USER_ID=$(curl -s -H "Authorization: Bearer ${TOKEN}" \
"${KC}/admin/realms/${REALM}/users?username=taro.yamada&exact=true" | jq -r '.[0].id')
curl -s -H "Authorization: Bearer ${TOKEN}" "${KC}/admin/realms/${REALM}/users/count"
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${KC}/admin/realms/${REALM}/users?first=100&max=100&briefRepresentation=true"
一覧のmaxは省略すると100件です。全件を同期するなら、countで総数を取り、firstを100ずつ進めて回します。briefRepresentation=trueにすると属性を省いた軽い応答になり、件数の多いレルムで転送量を抑えられます。
レルムロールの割り当てとSMTP設定を使うパスワード再設定メールの送信
ロールの割り当ては、ロールの表現をそのまま配列に入れてrole-mappings/realmへPOSTします。メール送信のexecute-actions-emailは、レルムにSMTPの設定が無いと送れません。
ROLE=$(curl -s -H "Authorization: Bearer ${TOKEN}" \
"${KC}/admin/realms/${REALM}/roles/app-user")
curl -s -o /dev/null -w "%{http_code}\n" -X POST \
"${KC}/admin/realms/${REALM}/users/${USER_ID}/role-mappings/realm" \
-H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" \
-d "[${ROLE}]"
curl -s -o /dev/null -w "%{http_code}\n" -X PUT \
"${KC}/admin/realms/${REALM}/users/${USER_ID}/execute-actions-email?lifespan=86400" \
-H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" \
-d '["UPDATE_PASSWORD","VERIFY_EMAIL"]'
どちらも成功時は204です。lifespanはメール内リンクの有効秒数で、例では24時間にしています。初期パスワードを渡さずにメールで本人に設定させる運用なら、作成時のcredentialsを省いてこのメールだけを送る形にできます。
退職者の無効化はGETした表現を書き換えてPUTしセッションも切る
退職者は削除より無効化が安全です。監査ログと紐付いたユーザーIDが残るからです。PUT /users/{id}には、一度GETした表現のenabledだけをfalseに変えて送り返します。
curl -s -H "Authorization: Bearer ${TOKEN}" "${KC}/admin/realms/${REALM}/users/${USER_ID}" \
| jq '.enabled = false' > user.json
curl -s -o /dev/null -w "%{http_code}\n" -X PUT \
"${KC}/admin/realms/${REALM}/users/${USER_ID}" \
-H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -d @user.json
curl -s -o /dev/null -w "%{http_code}\n" -X POST \
"${KC}/admin/realms/${REALM}/users/${USER_ID}/logout" \
-H "Authorization: Bearer ${TOKEN}"
GETした表現を戻す形にしておけば、ほかの属性を意図せず書き換える心配がありません。最後のlogoutは、そのユーザーの全セッションを消します。ただし発行済みのアクセストークンを署名の検証だけで受け入れるAPIでは、そのトークンは期限まで通ります。寿命を短く保つのはこのためです。
Node.jsから呼ぶ場合:keycloak-admin-clientで同じ処理を書く方法
アプリの中で呼ぶなら、curlを組み立てるより公式のクライアントライブラリが楽です。npmの@keycloak/keycloak-admin-clientはサーバーと同じ26.8.1が最新です。
client_credentialsで認証し58秒ごとに取り直す公式READMEの書き方
公式READMEは、リフレッシュトークンが無いclient_credentialsではauthを58秒ごとに呼び直す例を載せています。同じ考え方で、ユーザー作成とロール付与を書くと次のようになります。
import KcAdminClient from '@keycloak/keycloak-admin-client';
const kc = new KcAdminClient({ baseUrl: 'http://localhost:8080', realmName: 'myapp' });
const credentials = {
grantType: 'client_credentials',
clientId: 'user-sync',
clientSecret: process.env.KC_CLIENT_SECRET,
};
await kc.auth(credentials);
setInterval(() => kc.auth(credentials), 58 * 1000);
const { id } = await kc.users.create({
username: 'taro.yamada',
email: process.env.NEW_USER_EMAIL,
enabled: true,
});
const role = await kc.roles.findOneByName({ name: 'app-user' });
await kc.users.addRealmRoleMappings({ id, roles: [{ id: role.id, name: role.name }] });
呼んでいるのは前章と同じエンドポイントなので、必要なロールも変わりません。トークンの寿命を5分以上に延ばしているレルムでも、58秒の間隔はそのままで害はありません。
Keycloak APIで詰まりやすいエラーと応答コードごとの切り分け
Admin REST APIのエラーは、本文が短いか空のことが多く、応答コードから原因を絞るのが早道です。
401・403・404・409の4つで原因を切り分ける確認順
| コード | よくある原因 | 確認すること |
|---|---|---|
| 401 | トークン切れ・別レルムのトークン | expires_inとトークンのissのレルム名 |
| 403 | 管理ロール不足 | トークン内の管理ロール |
| 404 | clientIdと内部IDの取り違え | パスに入れたのがUUIDか |
| 409 | 同じusernameかemailのユーザーが既存 | exact=trueで検索して既存IDを使う |
表の403では、トークンのresource_accessにmanage-usersなどの管理ロールがあるかを確認してください。403で最初に疑うのは、サービスアカウントにロールを付けたのにスコープ側へ割り当てていないケースです。トークンをデコードしてrealm-managementのロールが空なら、前述の手順4が抜けています。409は作成処理を再実行したときに出やすいので、同期バッチは「検索して無ければ作成」の順に組みます。
Admin REST APIで連携を自作する判断:採用する条件と見送る場面
APIで何でも書けるぶん、作らなくてよい連携まで自作しがちです。採用と見送りの線を条件で示します。
会員DBや人事データとの同期をAPIで組むべき条件とSCIM・LDAPとの使い分け
APIでの自作が合うのは、自社サービスの会員登録画面からKeycloakにユーザーを作る場合と、正本がCSVや独自DBで標準プロトコルを話せない場合です。入社・異動・退職を夜間バッチで反映する程度なら、本記事の4つのAPIで足ります。
見送るべきなのは、正本がLDAPやActive Directoryの場合です。User Federationで読み込めば同期のコードは要りません。SaaS側がSCIMを話すなら、SCIMでのプロビジョニングに寄せたほうが保守の手間が減ります。26.8系の管理ガイドにはSCIM APIがAdmin REST APIと同じ権限モデルで動くとの記載もあります。
masterレルムの管理者資格情報をアプリに持たせる構成を避ける理由
公式ガイドの最初の例どおり、masterのadminでトークンを取るコードを本番に残す構成は採用しません。そのトークンは全レルムの全設定を変えられ、漏えい時の被害がKeycloak全体に及ぶからです。管理ガイドもmasterはレルムの作成と管理だけに使うよう書いています。
レルムごとにサービスアカウントを分け、ロールをmanage-usersとview-realmに絞れば、漏れても影響はそのレルムのユーザー管理に留まります。Client Secretは定期的に再生成し、Keycloak自体も修正版へ更新する手順と合わせて運用してください。権限設計からID連携の実装までまとめて任せたい場合は、一創の認証基盤・ID管理システム開発で、既存システムとの同期方式の選定から相談を受けています。
よくある質問
Keycloak APIを使い始める開発者からよく出る質問に、26.8.1時点の仕様で答えます。
Keycloak APIのドキュメントはどこにありますか?
エンドポイントの一覧はkeycloak.orgの「Keycloak Admin REST API」リファレンスにあり、同じ場所のopenapi.jsonで機械的に読めます。トークンの取り方はServer Developer Guide、管理ロールの意味はServer Administration Guideという分担です。版ごとにURLのlatestを26.8.1のような版番号に替えると、その版の内容に固定できます。
admin-cliで取ったトークンがすぐ使えなくなるのはなぜですか?
masterレルムのトークン寿命が短く設定されているためで、公式ガイドも既定で1分と書いています。スクリプトの途中で401が出たら、トークンを取り直してください。寿命を延ばすより、本記事のようにレルムごとのサービスアカウントへ切り替えるほうが、権限も絞れて安全です。
Keycloak APIでユーザーのパスワードを直接設定できますか?
ユーザーのパスワードを直接設定することは可能です。PUT /admin/realms/{realm}/users/{id}/reset-passwordにtype・value・temporaryを持つJSONを送ると、204で設定されます。レルムのパスワードポリシーに合わない値を送った場合の応答は400です。本人に決めさせたい場合は、execute-actions-emailでUPDATE_PASSWORDを送る方法を選びます。
グループへの追加もAPIでできますか?
できます。PUT /admin/realms/{realm}/users/{id}/groups/{groupId}で、本文なしの呼び出しで所属させられます。groupIdはグループ名ではなく内部IDです。ロールをグループに持たせて所属で権限を配る設計は、Keycloakの権限モデルで扱っています。
Docker上のKeycloakでも同じURLで呼べますか?
呼べます。パスは同じで、先頭のホスト名とポートが変わるだけです。リバースプロキシの後ろに置く場合は、/admin/を外部に公開しない構成が多いため、同期バッチは内部ネットワークから呼びます。公開パスの絞り方はKeycloak Dockerの本番構成で解説しています。
関連記事
- Keycloakとは?Oktaとの違いと連携手順|Auth0・Cognito比較で導入を判断【2026年10月】:Keycloakの機能と他製品との違いを確認できます。
- Keycloakのデータベース設定と使い方|PostgreSQL接続・対応DB・バックアップから権限モデルまで:起動・DB設定とロール・グループの設計を扱っています。
- Keycloak Dockerの本番構成:Composeでの起動とリバースプロキシ・ヘルスチェックの設定:APIを呼ぶ先のKeycloakを本番構成で立てる手順です。
- OAuthとは?OAuth 2.0の仕組み・認可フローと認証との違い、OAuth 2.1の変更点をわかりやすく解説:client_credentialsを含む認可フローの前提知識です。
- 認証・ID管理とは?MFA・SSO・OIDC・IDaaSの違いと選定を解説【2026年版】:自前のKeycloakとIDaaSを比べる際の全体像です。