Keycloak | CLI

The web UI of Keycloak works well for manual setup—but what about infrastructure-as-code workflows or CI/CD pipelines? Enter the Admin CLI (kcadm.sh), Keycloak's powerful command-line interface that maps directly to the Admin REST API.

In this article, we'll build a complete working setup from scratch using only the CLI and show how easy it is to manage a realm, client, role, group, and user. We'll also request an access token to verify that the setup works.

We'll be using Keycloak version 26.7.1. If you are using a different version, verify that the command syntax has not changed.

You can find the complete Keycloak Admin CLI documentation here.

Let's get started!

Prerequisites

To follow along with this article, please ensure that you have some containerization tool (Docker, Podman, etc.) installed on your machine.

Important notes

Note 1: We will use two terminals: one to run the Keycloak Docker container and another for the CLI.

Note 2. Some comments are labeled [Optional]. These optional commands are included to demonstrate additional Keycloak endpoints for managing resources.

Start Keycloak Docker container

In one terminal, let's run the following command to start a Keycloak Docker container:

docker run --rm \
  --name keycloak \
  -p 8080:8080 \
  -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
  -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
  quay.io/keycloak/keycloak:26.7.1 start-dev

Wait for it to start before proceeding.

Download Keycloak Zip

Go ahead and download the Keycloak ZIP file from the official Keycloak downloads page. Then, unzip it in your workspace.

Keycloak includes the Admin CLI in its server distribution, along with execution scripts located in the bin directory. We will use the kcadm.sh script.

Open a terminal and navigate to the Keycloak root folder you just unzipped. From now on, we will use this terminal to run the Admin CLI.

Exploring the commands

Run the following help command to check the available commands:

./bin/kcadm.sh --help

It should return:

Keycloak Admin CLI

Use 'kcadm.sh config credentials' command with username and password to start a session against a specific
server and realm.

For example:

  $ kcadm.sh config credentials --server http://localhost:8080 --realm master --user admin
  Enter password:
  Logging into http://localhost:8080 as user admin of realm master

Any configured username can be used for login, but to perform admin operations the user
needs proper roles, otherwise operations will fail.

Usage: kcadm.sh COMMAND [ARGUMENTS]

Global options:
  -x            Print full stack trace when exiting with error
  --help        Print help for specific command
  --config      Path to the config file (~/.keycloak/kcadm.config by default)

Commands:
  config        Set up credentials, and other configuration settings using the config file
  create        Create new resource
  get           Get a resource
  update        Update a resource
  delete        Delete a resource
  get-roles     List roles for a user or a group
  add-roles     Add role to a user or a group
  remove-roles  Remove role from a user or a group
  set-password  Re-set password for a user
  help          This help

Use 'kcadm.sh help <command>' for more information about a given command.

The Admin CLI performs CRUD operations against the Admin REST API, wrapping endpoints with simplified commands:

./bin/kcadm.sh create ENDPOINT [ARGUMENTS] # POST
./bin/kcadm.sh get ENDPOINT [ARGUMENTS]    # GET
./bin/kcadm.sh update ENDPOINT [ARGUMENTS] # PUT
./bin/kcadm.sh delete ENDPOINT [ARGUMENTS] # DELETE

Log in with the admin CLI (master realm)

Let's authenticate as the admin user from the "master" realm using direct username/password credentials. We need to do it once per terminal:

./bin/kcadm.sh config credentials \
  --server http://localhost:8080 \
  --realm master \
  --user admin \
  --password admin

You should get

Logging into http://localhost:8080 as user admin of realm master

Manage a Realm

Creating the realm "my-realm"

Let's create a new realm with the name "my-realm" and with the property enabled set to true to indicate that the realm is active. Here is the command:

./bin/kcadm.sh create realms \
  -s realm=my-realm \
  -s enabled=true

It should return:

Created new realm with id 'my-realm'

Note: If you're unsure about any command (like create above), just run: ./bin/kcadm.sh create --help. It should return the explanation and usage examples.

Updating the realm "my-realm"

Let's update the realm "my-realm" by setting the registrationAllowed property to true, using the following command:

./bin/kcadm.sh update realms/my-realm \
  -s registrationAllowed=true

[Optional] Retrieving all realms

To retrieve all realms, use the following command:

./bin/kcadm.sh get realms --fields realm

It should return:

[ {
  "realm" : "master"
}, {
  "realm" : "my-realm"
} ]

Note: Adding the --fields flag lets you select which fields you want in the response, instead of retrieving everything.

[Optional] Retrieving the realm "my-realm"

To retrieve a specific realm, in this case "my-realm," use the following command:

./bin/kcadm.sh get realms/my-realm --fields realm,registrationAllowed

It should return:

{
  "realm" : "my-realm",
  "registrationAllowed" : false
}

[Optional] Deleting the realm "my-realm"

To delete the realm "my-realm," use the following command:

./bin/kcadm.sh delete realms/my-realm

Manage a Client

Assuming you followed the previous step to create the realm "my-realm."

Creating the client "my-client"

Let's create a new client with the name "my-client" and with the property redirectUris set to ["http://localhost:9080/*"]. Here is the command:

./bin/kcadm.sh create clients \
  -r my-realm \
  -s clientId=my-client \
  -s 'redirectUris=["http://localhost:9080/*"]'

The response should be something like:

Created new client with id '<my-client-id-generated-by-keycloak>'

The "my-client" ID (highlighted in bold) is present in the response. Let's copy it and set the MY_CLIENT_ID environment variable:

MY_CLIENT_ID=<my-client-id-generated-by-keycloak>

Updating the client "my-client"

Let's update "my-client" by setting the property directAccessGrantsEnabled to true, using the command below:

./bin/kcadm.sh update clients/$MY_CLIENT_ID \
  -r my-realm \
  -s directAccessGrantsEnabled=true

[Optional] Retrieving all clients

To retrieve all clients, use the following command:

./bin/kcadm.sh get clients --fields id,clientId

[Optional] Retrieving the client "my-client"

To retrieve a specific client, in this case "my-client," use the following command:

./bin/kcadm.sh get clients/$MY_CLIENT_ID \
  -r my-realm \
  --fields id,clientId,directAccessGrantsEnabled

[Optional] Deleting the client "my-client"

To delete the client named "my-client," use the following command:

./bin/kcadm.sh delete clients/$MY_CLIENT_ID \
  -r my-realm

Manage a Client Role

Assuming you followed the previous steps to create the realm "my-realm" and the client "my-client."

Creating the client role "MY_ROLE" for the client "my-client"

Let's create a new client role named "MY_ROLE" for "my-client." Here is the command:

./bin/kcadm.sh create clients/$MY_CLIENT_ID/roles \
  -r my-realm \
  -s name=MY_ROLE

The response should be like this:

Created new role with id 'MY_ROLE'

[Optional] Retrieving all roles of the client "my-client"

To retrieve all "my-client" roles, use the following command:

./bin/kcadm.sh get clients/$MY_CLIENT_ID/roles \
  -r my-realm

[Optional] Retrieving the role "MY_ROLE" of the client "my-client"

To retrieve a specific client role, in this case "MY_ROLE," use the following command:

./bin/kcadm.sh get clients/$MY_CLIENT_ID/roles/MY_ROLE \
  -r my-realm

[Optional] Deleting the role "MY_ROLE" of the client "my-client"

To delete the client role "MY_ROLE" of the client "my-client," use the following command:

./bin/kcadm.sh delete clients/$MY_CLIENT_ID/roles/MY_ROLE \
  -r my-realm

Manage a Group

Assuming you followed the previous steps to create the realm "my-realm", the client "my-client" and the client role "MY_ROLE."

Creating the group "MY_GROUP"

Let's create a group named "MY_GROUP." Here is the command:

./bin/kcadm.sh create groups \
  -r my-realm \
  -s name=MY_GROUP

It should return something like:

Created new group with id '<my-group-id-generated-by-keycloak>'

The "MY_GROUP" ID (highlighted in bold) is present in the response. Let's copy it and set the MY_GROUP_ID environment variable:

MY_GROUP_ID=<my-group-id-generated-by-keycloak>

Assigning the client role "MY_ROLE" to group "MY_GROUP"

First, let's retrieve the client role information:

./bin/kcadm.sh get clients/$MY_CLIENT_ID/roles/MY_ROLE \
  -r my-realm

We should get something like:

{ "id" : "<my-role-id-generated-by-keycloak>", "name" : "MY_ROLE", ... }

Let's copy the value in the id field and set it to the MY_ROLE_ID environment variable:

MY_ROLE_ID=<my-role-id-generated-by-keycloak>

Then, run the command below to perform the assignment:

./bin/kcadm.sh add-roles \
  -r my-realm \
  --gname MY_GROUP \
  --cclientid my-client \
  --rolename MY_ROLE

[Optional] Retrieving all groups

To retrieve all groups, use the following command:

./bin/kcadm.sh get groups \
  -r my-realm

[Optional] Retrieving the group "MY_GROUP"

To retrieve a specific group, in this case "MY_GROUP," use the following command:

./bin/kcadm.sh get groups/$MY_GROUP_ID \
  -r my-realm

[Optional] Deleting the group "MY_GROUP"

To delete the group "MY_GROUP," use the following command:

./bin/kcadm.sh delete groups/$MY_GROUP_ID \
  -r my-realm

Manage a User

Assuming you followed the previous steps to create the realm "my-realm", the client "my-client", the client role "MY_ROLE" and the group "MY_GROUP."

Creating the user "my-user"

Let's create a new user whose username is "my-user." Here is the command:

./bin/kcadm.sh create users \
  -r my-realm \
  -s username=my-user \
  -s enabled=true

It should return something like:

Created new user with id '<my-user-id-generated-by-keycloak>'

The "my-user" ID (highlighted in bold) is present in the response. Let's copy it and set the MY_USER_ID environment variable:

MY_USER_ID=<my-user-id-generated-by-keycloak>

Setting a password to the user "my-user"

We can set the password "123" for "my-user" using the following command:

./bin/kcadm.sh set-password \
  -r my-realm \
  --userid $MY_USER_ID \
  --new-password 123 \
  --temporary=false

Updating the user "my-user"

We can update the user "my-user" by setting, for instance, the email property using the command below:

./bin/kcadm.sh update users/$MY_USER_ID \
  -r my-realm \
  -s email=my-user@test.com

[Optional] Retrieving all users

To retrieve all users, use the following command:

./bin/kcadm.sh get users -r my-realm \
  --fields id,username,email,emailVerified

[Optional] Retrieving the user "my-user"

To retrieve a specific user, in this case "my-user," use the following command:

./bin/kcadm.sh get users/$MY_USER_ID \
  -r my-realm

Assigning the group "MY_GROUP" to user "my-user"

Let's assign the group "MY_GROUP" to the user "my-user" using the command below:

./bin/kcadm.sh update users/$MY_USER_ID/groups/$MY_GROUP_ID \
  -r my-realm

[Optional] Getting "my-user" groups

To retrieve all groups "my-user" belongs to, use the following command:

./bin/kcadm.sh get users/$MY_USER_ID/groups \
  -r my-realm

[Optional] Deleting the user "my-user"

To delete the user named "my-user," use the following command:

./bin/kcadm.sh delete users/$MY_USER_ID \
  -r my-realm

Get user Access Token

Assuming you followed the previous step to create the realm "my-realm", the client "my-client", the client role "MY_ROLE", the group "MY_GROUP" and the user "my-user."

Getting the secret of the client "my-client"

To obtain the "my-client" secret, use the following command:

./bin/kcadm.sh get clients/$MY_CLIENT_ID/client-secret \
  -r my-realm

It should return something like:

{
  "type" : "secret",
  "value" : "cVNxRvhbqC3D23UxnbiEdMOZbMA4..."
}

Let's copy the secret present in the value field to the MY_CLIENT_SECRET environment variable:

MY_CLIENT_SECRET=...

Disabling the required action Verify Profile

For testing purposes, let's disable the required action Verify Profile. Otherwise, we won't be able to retrieve a user access token (discussed in the next step):

./bin/kcadm.sh update authentication/required-actions/VERIFY_PROFILE \
  -r my-realm \
  -s enabled=false \
  -s defaultAction=false \
  -s priority=90

Getting "my-user" access token for the client "my-client"

Let's obtain a "my-user" access token for the client "my-client" using the following command:

curl -i -X POST "http://localhost:8080/realms/my-realm/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=my-user" \
  -d "password=123" \
  -d "grant_type=password" \
  -d "client_secret=$MY_CLIENT_SECRET" \
  -d "client_id=my-client"

It should return something like:

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI...",
    "expires_in": 300,
    "refresh_expires_in": 1800,
    "refresh_token": "eyJhbGciOiJIUzUxMiIsInR5cCI...",
    "token_type": "Bearer",
    "not-before-policy": 0,
    "session_state": "eQzWuP4_PBfxZqOFSqkAuAMM",
    "scope": "profile email"
}

We can inspect the access token using Skycloak's jwt-token-analyzer. After decoding it, we get the following header and payload:

Header

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "KZC4n_xILRzWfIxoDRjyqIUeX0UBn4_Llm31EqfCloI"
}

Payload

{
  "exp": 1786896077,
  "iat": 1786895777,
  "jti": "onrtro:db86ebb5-a307-2aa0-0beb-fe75a8af5ff9",
  "iss": "http://localhost:8080/realms/my-realm",
  "aud": "account",
  "sub": "cdf5838e-c87f-4bfe-aa74-d5cc4a4bcb15",
  "typ": "Bearer",
  "azp": "my-client",
  "sid": "eQzWuP4_PBfxZqOFSqkAuAMM",
  "acr": "1",
  "allowed-origins": [
    "http://localhost:9080"
  ],
  "realm_access": {
    "roles": [
      "offline_access",
      "uma_authorization",
      "default-roles-my-realm"
    ]
  },
  "resource_access": {
    "my-client": {
      "roles": [
        "MY_ROLE"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "scope": "profile email",
  "email_verified": false,
  "preferred_username": "my-user",
  "email": "my-user@test.com"
}

Shutdown

In the terminal where Keycloak is running, press Ctrl+C to stop the application.

Conclusion

By using Keycloak's Admin CLI, we've seen how simple it is to automate Keycloak configuration and integrate it into your CI/CD pipelines. With just a few commands, you can manage realms, clients, roles, groups, and users — all without touching the web UI. This approach keeps your identity management consistent, repeatable, and ready for version control.

Thanks for Reading

If you found this article useful, here are a few ways you can support my work:

  • 👏 Clap and highlight sections you found valuable — it helps this article reach more readers.
  • 💬 Join the conversation by leaving a response. I enjoy discussing ideas and answering questions.
  • 🔔 Follow me on Medium | LinkedIn | X | GitHub.
  • ✉️ Subscribe to my newsletter to get my latest posts and insights directly in your inbox.
  • Support my writing: If you'd like to support the time and effort behind these articles, you can
None