1

I want to create a user and assign a client role with it in a single API in Keycloak I have attached the details.

I have this API

http://testkeycloak.com:8085/auth/admin/realms/engineer/users

{   
    "enabled":true,
    "username":"joshbiden",
    "email":"email@gmail.com",
    "firstName":"Josh",
    "lastName":"biden",
    "attributes": 
    {
        "Mobile Number":"3333332332"
    },
    "clientRoles": 
    {
        "name": "DEVELOPER"
    },
    "credentials":
    [
    {
        "type":"password",
        "value":"rollback",
        "temporary":false
    }
    ]
}

CLIENT ROLE - DETAILS

    {
        "id": "32e432da-d0c0-45f8-a67d-f3146b7a24b4",
        "name": "DEVELOPER",
        "composite": false,
        "clientRole": true,
        "containerId": "343434-7631-4187-ac76-ad78de119b90"
    }

How can I assign two clients' roles to the USER, I have tried to add users but facing an unknown error. Let me know any solution for the same

dreamcrash
  • 47,137
  • 25
  • 94
  • 117
krishan
  • 47
  • 2
  • 8

3 Answers3

7

I want to create a user and assign a client role with it in a single API in Keycloak I have attached the details.

Unfortunately, it is impossible to do that with a single API call, even though the Keycloak Admin rest API documentation infers otherwise. This can be confirmed by looking at this GitHub issue. Quoting the reply from that thread (from the Keycloak Project Leader Stian Thorgersen):

So, unfortunately, the answer from @Devendra Mahajan is simply not correct.


The solution is to perform two calls, namely:

  1. one to create the user
  2. another to assign the roles

First create the user using the endpoint POST /{realm}/users and with the following data (without the role):

{
  "username": "joshbiden",
  "enabled": true,
  "firstName": "Josh",
  "lastName": "biden",
  "email": "email@gmail.com",
  "attributes": {
    "Mobile Number": [
      "3333332332"
    ]
  },
  "credentials": [{
    "type":"password",
    "value":"rollback",
    "temporary":false
  }]
}

Second, you assign the role using the endpoint :

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

with the data:

[{
  "id": "32e432da-d0c0-45f8-a67d-f3146b7a24b4",
  "name": "DEVELOPER",
  "composite": false,
  "clientRole": true,
  "containerId": "343434-7631-4187-ac76-ad78de119b90"
}]

Step-by-Step

Warning: The /auth path was removed starting with Keycloak 17 Quarkus distribution. So you might need to remove the /auth from the endpoint calls presented on this answer.

To use Keycloak Admin REST API you need an access token from a user with the proper permissions. I will be using the admin user from the master realm:

curl "https://${KEYCLOAK_HOST}/auth/realms/master/protocol/openid-connect/token" \
    -d "client_id=admin-cli" \
    -d "username=$ADMIN_NAME" \
    -d "password=$ADMIN_PASSWORD" \
    -d "grant_type=password"

You will get a JSON with the admin's token. Extract the value of property access_token from that response. Let us save it in the variable $ACCESS_TOKEN for later reference.

To create the user in your realm $REALM_NAME:

curl -X POST "https://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/users"
     -H "Content-Type: application/json" \
     -H "Authorization: bearer $ACCESS_TOKEN" \
     -d "${USER_JSON_DATA}" 

For those that need you can also have a look at my scripts to automatize the user creation on GitHub, namely this or this.

To assign the client role to the user you need the know beforehand the following fields:

  1. id of the user
  2. id of the client
  3. client role representation

To get the user id from your realm $REALM_NAME:

curl -X GET "https://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/users/?username=${USERNAME}" \
     -H "Content-Type: application/json" \
     -H "Authorization: bearer $ACCESS_TOKEN"

From the response extract the user id for example as follows

jq -r ".[] | select(.username==\"$USERNAME\")" | jq -r id

and save it in the variable ${USER_ID}.

To get the client id call the endpoint get clients with the parameter clientID:

curl -X GET "${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/clients?clientId=${CLIENT_ID}" \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer ${ACCESS_TOKEN}"

Extract id from the response (e.g., jq -r .[0].id) and save it in variable ${ID_OF_CLIENT}.

With the previous id you can get the client role as follows:

curl -X GET "http://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/clients/${ID_OF_CLIENT}/roles/${ROLE_NAME}" \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer ${ACCESS_TOKEN}"

Save the json response in ${CLIENT_ROLE}, and assign the role to the user as follows:

curl  -X POST "http://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/users/${USER_ID}/role-mappings/clients/${ID_OF_CLIENT}" \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer ${ACCESS_TOKEN}" \
        -d "${CLIENT_ROLE}"

I have created scripts for the aforementioned steps that can be accessed here and executed using the script getClientRoleByName.sh.

dreamcrash
  • 47,137
  • 25
  • 94
  • 117
  • According to the documentation, the endpoint `POST /{realm}/users/{id}/role-mappings/clients/{id of client}` accepts only a single role (RoleRepresentation). Yet, in your example you used an array. Is that the case? Is the doc incorrect or was it a mistake on your part? I'm asking because I'm searching for a way to add multiple roles to a user at once, but according to the docs, that's not possible, only with multiple calls. Thanks! – eestein Jul 23 '23 at 12:11
  • Just for reference: https://www.keycloak.org/docs-api/22.0.1/rest-api/index.html – eestein Jul 23 '23 at 12:19
  • @eestein Hi, in my example I am also just assigning one role – dreamcrash Jul 23 '23 at 20:47
  • Thanks for replying, I see that, but you're using an array, right? `[{}]` – eestein Jul 24 '23 at 22:48
  • Hi, as far as I can see no, I get the server response from the serve in an array. Can you past the line where you see the array? – dreamcrash Jul 25 '23 at 20:24
  • Sure, there you go https://ibb.co/nRNXrZP but it's fine, maybe it was a mistake, since you had a single record in mind. – eestein Jul 26 '23 at 06:40
  • @eestein On the api you have /{realm}/users/{id}/role-mappings/realm and the parameter is an array of roles – dreamcrash Aug 03 '23 at 20:12
0

Try This,

{
  "enabled": true,
  "username": "joshbiden",
  "email": "email@gmail.com",
  "firstName": "Josh",
  "lastName": "biden",
  "attributes": {
    "Mobile Number": "3333332332"
  },
  "clientRoles": {
    "<name-of-the-client-in-realm>": ["DEVELOPER"]
  },
  "credentials": [
    {
      "type": "password",
      "value": "rollback",
      "temporary": false
    }
  ]
}
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 12 '22 at 07:11
  • 1
    Hi there, unfortunately this answer does not work – dreamcrash Jan 03 '23 at 13:56
0

This can be achieved using the partial import API

POST /{realm}/partialImport

With this API you can also import multiple users in one call. This is not a solution for update though.

Body sample:

{
"users": [
    {
        "username": "user1",
        "enabled": true,
        "totp": false,
        "emailVerified": true,
        "firstName": "First name",
        "lastName": "Last name",
        "disableableCredentialTypes": [],
        "requiredActions": [],
        "notBefore": 0,
        "access": {
            "manageGroupMembership": true,
            "view": true,
            "mapRoles": true,
            "impersonate": true,
            "manage": true
        },
        "groups": [
            
        ],
        "realmRoles": [
            
        ]
    },
    {
        "username": "user2",
        "enabled": true,
        "totp": false,
        "emailVerified": true,
        "firstName": "User 2",
        "lastName": "Last name",
        "disableableCredentialTypes": [],
        "requiredActions": [],
        "notBefore": 0,
        "access": {
            "manageGroupMembership": true,
            "view": true,
            "mapRoles": true,
            "impersonate": true,
            "manage": true
        },
        "groups": [

        ],
        "realmRoles": [
            "some realm role"
        ],
        "clientRoles": {
            "some client": [
                "some client role"
            ]
        }
    }
]

}

Yoni Reiss
  • 320
  • 2
  • 8