Forivin
Forivin

Reputation: 15508

Create Keycloak client using REST API from Bash

I have a script that automatically creates a local Kubernetes cluster (for development purposes), installing a bunch of applications including Keycloak on it. The next step that I need to automate is creating some Keycloak resources. I need to:

I have managed to create a realm through the API, but creating a client or user is causing errors.

This is my code:

##################### Create variables ########################
LB_ADDRESS="192.168.49.3.nip.io"
KEYCLOAK_URL="https://auth.${LB_ADDRESS}/auth"
REALM_NAME="account-1"
ADMIN_USERNAME="admin"
ADMIN_PASSWORD="aic"

project_id_1="7677"

client_1_id="ais-${project_id_1}"
client_1_name="project${project_id_1}.${LB_ADDRESS}"

user_1_name="myuser"
user_1_password="mypassword"

group_name="$client_1_name"

#################### Create helper functions ####################
function get_access_token() {
    curl --insecure -s -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=password&client_id=admin-cli&username=${ADMIN_USERNAME}&password=${ADMIN_PASSWORD}" | jq -r '.access_token'
}

function create_realm() {
    curl --insecure -s -X POST "${KEYCLOAK_URL}/admin/realms" -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -d "{
        \"realm\": \"$1\",
        \"enabled\": true
    }"
}

function create_client() {
    client_id="$1"
    client_name="$2"
    curl --insecure -X POST "${KEYCLOAK_URL}/admin/realms/$REALM_NAME/clients" \
    -H "Authorization: Bearer $ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
        "clientId": "'"$client_id"'",
        "name": "'"$client_name"'",
        "standardFlowEnabled": true,
        "directAccessGrantsEnabled": true,
        "serviceAccountsEnabled": true,
        "publicClient": false,
        "attributes": {
            "validRedirectUris": ["*"],
            "webOrigins": ["*"]
        }
    }'
}

function create_user() {
    username="$1"
    password="$2"
    curl --insecure -X POST "${KEYCLOAK_URL}/admin/realms/$REALM_NAME/users/" \
    -H "Authorization: Bearer $ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
        "username": "'"$username"'",
        "emailVerified": true,
        "serviceAccountsEnabled": true,
        "credentials": [{
          "type": "password",
          "value": "'"$password"'",
          "temporary": false
        }]
    }'
}

function assign_role_to_user() {
    client="$1"
    username="$2"
    role="$3"
    curl --insecure -X POST "${KEYCLOAK_URL}/admin/realms/$REALM_NAME/users/${username}/role-mappings/clients/${client}" \
    -H "Authorization: Bearer $ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '[{
        "id": "'"$role"'",
        "composite": true
    }]'
}

function add_user_to_group() {
    group="$1"
    username="$2"
    curl --insecure -X PUT "${KEYCLOAK_URL}/admin/realms/$REALM_NAME/users/${username}/groups/${group}" \
    -H "Authorization: Bearer $ACCESS_TOKEN"
}

################### Access Keycloak API #######################
ACCESS_TOKEN="$(get_access_token)"

create_realm $REALM_NAME
create_client "$client_1_id" "$client_1_name"
create_user "$user_1_name" "$user_1_password"
assign_role_to_user "$client_1_id" "$user_1_name" "my-composite-role"
add_user_to_group "$group_name" "$user_1_name"

The access token is retrieved successfully, the realm is created successfully, but then it fails:

create_client "$client_1_id" "$client_1_name" results in:

{"error":"HTTP 401 Unauthorized"}

What am I doing wrong?

Edit: Do I maybe have to create an access token for the newly created realm before creating resources inside of it? But that seems impossible because the newly created realm doesn't have an admin account by default and in order to create one, I would need an access token again.

Btw I'm using Keycloak v21.1.1: https://quay.io/repository/keycloak/keycloak?tab=tags&tag=21.1.1

Upvotes: 2

Views: 1431

Answers (2)

dreamcrash
dreamcrash

Reputation: 51453

The first problem is that the json on the create client is wrong instead of:

-d '{
    "clientId": "'"$client_id"'",
    "name": "'"$client_name"'",
    "standardFlowEnabled": true,
    "directAccessGrantsEnabled": true,
    "serviceAccountsEnabled": true,
    "publicClient": false,
    "attributes": {
        "validRedirectUris": ["*"],
        "webOrigins": ["*"]
    }
}'

it should be:

-d '{
    "clientId": "'"$client_id"'",
    "name": "'"$client_name"'",
    "standardFlowEnabled": true,
    "directAccessGrantsEnabled": true,
    "serviceAccountsEnabled": true,
    "publicClient": false,
    "redirectUris": ["*"],
    "webOrigins": ["*"]
}'

Second on the user json the field 'serviceAccountsEnabled' does not actually exist in Keycloak, the closes thing you have to it is 'serviceAccountClientId'. So you user json should be :

-d '{
    "username": "'"$username"'",
    "emailVerified": true,
    "credentials": [{
      "type": "password",
      "value": "'"$password"'",
      "temporary": false
    }]
}'

Your 'assign_role_to_user' function is using the wrong endpoint. The endpoint is not:

"${KEYCLOAK_URL}/admin/realms/$REALM_NAME/users/${username}/role-mappings/clients/${client}"

but

POST /{realm}/users/{id}/role-mappings/clients/{client}

you need to use the 'id' of the user, not its username. Moreover, in the payload the 'id' should the role ID, have a look at this SO thread for more information.

Upvotes: 2

yoad
yoad

Reputation: 95

You can try creating the client in the realm step, that seems more correct to me,
The simple way to do this is to pre-define a realm and then export the JSON.
Anyway, I can suggest the following things to check:

  • make sure the ACCESS_TOKEN has not expired when the request is sent (default is short time)
  • 401 alone not really help to understand the issue
    (considering the fact that I assume that it worked in the creation of the realm)
    I would suggest checking keycloak logs for more information

Another thing I would suggest to consider, I don't know how you install the keycloak, but if you work with helm or argo you can provide a pre-defined realm on the startup

Upvotes: 0

Related Questions