Skip to content

Instantly share code, notes, and snippets.

@thomasdarimont
Last active April 23, 2024 09:02
Show Gist options
  • Save thomasdarimont/c4e739c5a319cf78a4cff3b87173a84b to your computer and use it in GitHub Desktop.
Save thomasdarimont/c4e739c5a319cf78a4cff3b87173a84b to your computer and use it in GitHub Desktop.
Using Keycloak Admin Client to create user with roles (Realm and Client level)
package demo.plain;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.CreatedResponseUtil;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import javax.ws.rs.core.Response;
import java.util.Arrays;
import java.util.Collections;
public class KeycloakAdminClientExample {
public static void main(String[] args) {
String serverUrl = "http://sso.tdlabs.local:8899/u/auth";
String realm = "acme";
// idm-client needs to allow "Direct Access Grants: Resource Owner Password Credentials Grant"
String clientId = "idm-client";
String clientSecret = "0d61686d-57fc-4048-b052-4ce74978c468";
// // Client "idm-client" needs service-account with at least "manage-users, view-clients, view-realm, view-users" roles for "realm-management"
// Keycloak keycloak = KeycloakBuilder.builder() //
// .serverUrl(serverUrl) //
// .realm(realm) //
// .grantType(OAuth2Constants.CLIENT_CREDENTIALS) //
// .clientId(clientId) //
// .clientSecret(clientSecret).build();
// User "idm-admin" needs at least "manage-users, view-clients, view-realm, view-users" roles for "realm-management"
Keycloak keycloak = KeycloakBuilder.builder() //
.serverUrl(serverUrl) //
.realm(realm) //
.grantType(OAuth2Constants.PASSWORD) //
.clientId(clientId) //
.clientSecret(clientSecret) //
.username("idm-admin") //
.password("admin") //
.build();
// Define user
UserRepresentation user = new UserRepresentation();
user.setEnabled(true);
user.setUsername("tester1");
user.setFirstName("First");
user.setLastName("Last");
user.setEmail("tom+tester1@tdlabs.local");
user.setAttributes(Collections.singletonMap("origin", Arrays.asList("demo")));
// Get realm
RealmResource realmResource = keycloak.realm(realm);
UsersResource usersRessource = realmResource.users();
// Create user (requires manage-users role)
Response response = usersRessource.create(user);
System.out.printf("Repsonse: %s %s%n", response.getStatus(), response.getStatusInfo());
System.out.println(response.getLocation());
String userId = CreatedResponseUtil.getCreatedId(response);
System.out.printf("User created with userId: %s%n", userId);
// Define password credential
CredentialRepresentation passwordCred = new CredentialRepresentation();
passwordCred.setTemporary(false);
passwordCred.setType(CredentialRepresentation.PASSWORD);
passwordCred.setValue("test");
UserResource userResource = usersRessource.get(userId);
// Set password credential
userResource.resetPassword(passwordCred);
// // Get realm role "tester" (requires view-realm role)
RoleRepresentation testerRealmRole = realmResource.roles()//
.get("tester").toRepresentation();
//
// // Assign realm role tester to user
userResource.roles().realmLevel() //
.add(Arrays.asList(testerRealmRole));
//
// // Get client
ClientRepresentation app1Client = realmResource.clients() //
.findByClientId("app-frontend-springboot").get(0);
//
// // Get client level role (requires view-clients role)
RoleRepresentation userClientRole = realmResource.clients().get(app1Client.getId()) //
.roles().get("user").toRepresentation();
//
// // Assign client level role to user
userResource.roles() //
.clientLevel(app1Client.getId()).add(Arrays.asList(userClientRole));
// Send password reset E-Mail
// VERIFY_EMAIL, UPDATE_PROFILE, CONFIGURE_TOTP, UPDATE_PASSWORD, TERMS_AND_CONDITIONS
// usersRessource.get(userId).executeActionsEmail(Arrays.asList("UPDATE_PASSWORD"));
// Delete User
// userResource.remove();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.thomasdarimont.keycloak</groupId>
<artifactId>keycloak-admin-client-example</artifactId>
<version>1.0.0.0-SNAPSHOT</version>
<properties>
<keycloak.version>8.0.2</keycloak.version>
<resteasy.version>3.9.1.Final</resteasy.version>
</properties>
<dependencies>
<dependency>
<artifactId>keycloak-admin-client</artifactId>
<groupId>org.keycloak</groupId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
</dependencies>
</project>
Copy link

ghost commented Aug 20, 2020

How to handle transaction in keycloak while implementing multiple tasks?
like create user and assign role in the same method. please find my sample code in the below link.
https://stackoverflow.com/questions/63446732/how-to-handle-transaction-between-multiple-operations-in-keycloak-using-java-key

@siddhanta-rath
Copy link

@dinohorvat doesn't work with 3.3.0.CR2 either

is this working now with the latest version?

{
    "username": "user11",
     enabled: true,
    "credentials": [{
    	"type": "password",
    	"value": "password"
    }],
    "realmRoles": ["employee"]
}

now can we create a user and assign the role at one call?

@chenweisomebody126
Copy link

hello,
i am trying to create user with this code but it gives an exception. "javax.ws.rs.NotAuthorizedException: HTTP 401 Unauthorized"

just have one realm and its name is master.

Keycloak keycloak = KeycloakBuilder.builder() //
.serverUrl(serverUrl) //
.realm(realm) //
.grantType(OAuth2Constants.PASSWORD) //
.clientId(clientId) //
.clientSecret(clientSecret) //
.username("{username}") //
.password("{password}") //
.build();

user is the admin of the realm.
it gives exception in this line;
keycloak.realm("master").users().create(user);

actually it gives this exception all lines which trying to get somethind from keycloak.
for example : keycloak.realm("master").toRepresentation();

You should check this

@Sairaj14
Copy link

this is my request body
{ "self" : null, "origin" : null, "createdTimestamp" : 1600694492110, "username" : "sairaj123", "enabled" : true, "totp" : false, "emailVerified" : false, "firstName" : "Sairaj", "lastName" : "Bhoite", "email" : "caped.crusader1417@gmail.com", "federationLink" : null, "serviceAccountClientId" : null, "attributes" : null, "credentials" : [{ "type":"password", "value":"sairaj123", "temporary":false }], "disableableCredentialTypes" : [ ], "requiredActions" : [ ], "federatedIdentities" : null, "realmRoles" : ["ROLE_TPP","ROLE_USER","ROLE_ADMIN"], "clientRoles" : null, "clientConsents" : null, "notBefore" : 0, "applicationRoles" : null, "socialLinks" : null, "groups" : null, "access" : { "manageGroupMembership" : true, "view" : true, "mapRoles" : true, "impersonate" : true, "manage" : true } }

Controller method

`@PostMapping("/keycloak/createUser")
public Object createUser(HttpServletRequest request , @Valid @requestbody UserRepresentation body) throws JsonProcessingException {
KeycloakSecurityContext context = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());

    Keycloak keycloak = KeycloakBuilder.builder()
        .serverUrl("http://localhost:8083/auth")
        .grantType(OAuth2Constants.PASSWORD)
        .realm("master")
        .clientId("admin-cli")
        .username("admin")
        .password("admin")
        .resteasyClient(
            new ResteasyClientBuilder()
                .connectionPoolSize(10).build()
        ).build();

    Response res = keycloak.realm("Myrealm").users().create(body);

    List<Response> list = new ArrayList<Response>();
    JSONArray jsonArr = new JSONArray();

    for (int i = 0; i < jsonArr.size(); i++) {
        JSONObject jsonObj = (JSONObject) jsonArr.get(i);
        ObjectMapper mapper = new ObjectMapper();
        Response response = mapper.readValue(jsonObj.toString(), Response.class);
        list.add(response);
    }
    return  list;
}`

i am able to create user , but the specified realm roles are not being mapped on keycloak instance

@linh-ebisolvn
Copy link

@dinohorvat doesn't work with 3.3.0.CR2 either

is this working now with the latest version?

{
    "username": "user11",
     enabled: true,
    "credentials": [{
    	"type": "password",
    	"value": "password"
    }],
    "realmRoles": ["employee"]
}

now can we create a user and assign the role at one call?

any progress on this?

@nzoelle24
Copy link

This is very useful thanks for sharing the code snippet.While i am developing i also got the 401 Unauthorized Error this was due to as mentioned in the code comments i didn't have necessary user roles for my users. Eg: idm-client and idm-admin. to assign above users for roles follow the following instructions in keycloak admin console .

idm-client
clients -> select app client-> service account role tab-> type relam management under client roles -> assign nessary roles and save
idm-admin
users-> select admin user-> role mappings tab-> type relam management under client roles -> assign nessary roles and save

Hope this will help someone.

Thank you 1000 times! big help

@danushka-eranga
Copy link

Was there a solution to the javax.ws.rs.NotAuthorizedException: HTTP 401 Unauthorized problem previously mentioned by @SaatTek? Same line of creating user (keycloak.realm(REALM).users().create(userRepresentation);)
I am using version 6.0.1. I have my own realm and am using the admin user and password.
Does KeycloakBuilder not authorise?
And the answer is it does not when the KeycloakBuilder object is created. It checks the credentials when it is used such as create. And to make it work, I needed the master user in the master realm. And then when creating, use the new realm.

Was there a solution to the javax.ws.rs.NotAuthorizedException: HTTP 401 Unauthorized problem previously mentioned by @SaatTek? Same line of creating user (keycloak.realm(REALM).users().create(userRepresentation);)
I am using version 6.0.1. I have my own realm and am using the admin user and password.
Does KeycloakBuilder not authorise?
And the answer is it does not when the KeycloakBuilder object is created. It checks the credentials when it is used such as create. And to make it work, I needed the master user in the master realm. And then when creating, use the new realm.

Do like below to build the keycloak instance.

Keycloak keycloak = KeycloakBuilder.builder() .serverUrl(serverUrl).realm(realm).grantType(OAuth2Constants.CLIENT_CREDENTIALS).clientId(clientId) .clientSecret(clientSecret).build();

@rc-bandit4461
Copy link

@dinohorvat doesn't work with 3.3.0.CR2 either

is this working now with the latest version?

{
    "username": "user11",
     enabled: true,
    "credentials": [{
    	"type": "password",
    	"value": "password"
    }],
    "realmRoles": ["employee"]
}

now can we create a user and assign the role at one call?

using Keycloak 13.0.1 and still having the same problem neither by REST API or Keycloak admin REST Client 13.0.1.

@shanmukakondaveti
Copy link

i am getting 401,400 and 403 exceptions when i tried to create user using this code,please help me how to connect to keycloak and create user in keycloak

@danushka-eranga
Copy link

danushka-eranga commented Jun 17, 2021

i am getting 401,400 and 403 exceptions when i tried to create user using this code,please help me how to connect to keycloak and create user in keycloak

cerate keycloak instance in this way

Keycloak keycloak = KeycloakBuilder.builder() .serverUrl(serverUrl).realm(realm).grantType(OAuth2Constants.CLIENT_CREDENTIALS).clientId(clientId) .clientSecret(clientSecret).build();

@rc-bandit4461
Copy link

i am getting 401,400 and 403 exceptions when i tried to create user using this code,please help me how to connect to keycloak and create user in keycloak

  1. Create a realm, Go to your realm in Keycloak, go to the users, create a user, just give it username, then save, go to credentials tab of the created user, and give it a password with "password temporary" option turned off.
  2. Go to role mappings of the user, Go to client roles, realm-management, assign the roles you want to this user so it can be authorized. If you want to create a user, then add the role "manage-users" and "query-users" to the user.
  3. Go to Clients, create a client and call it "idm-client" (just example). after that, go to "Access Type" in this client, by default its public, set it it to confidential, and set redirect uri to *. save settings and go to "credentials" tab inside "idm-client", copy the client-secret and replace it in the clientSecret variable in the java file. it should work
    image
    image
    image

@rc-bandit4461
Copy link

i am getting 401,400 and 403 exceptions when i tried to create user using this code,please help me how to connect to keycloak and create user in keycloak

cerate keycloak instance in this way

Keycloak keycloak = KeycloakBuilder.builder() .serverUrl(serverUrl).realm(realm).grantType(OAuth2Constants.CLIENT_CREDENTIALS).clientId(clientId) .clientSecret(clientSecret).build();

you can use this, but you need to go to your realm client => Service Accounts, and give it realm-management roles

@shanmukakondaveti
Copy link

hii,I successfully created User with the code,now my requirement is How to update the already saved user in Keyclok,when i try this it is creating new user not updating the existing one,can anyone help me how to meet my requirement?

@shanmukakondaveti
Copy link

please anyone provide solution to my question

@danushka-eranga
Copy link

please anyone provide solution to my question

public void updateUser(String userId, User user){

    RealmResource realmResource = this.keycloak.realm(realm)
    UsersResource usersResource = realmResource.users();
    UserResource userResource = usersResource.get(userId);
    UserRepresentation user = userResource.toRepresentation();

    user.setFirstName(user.getFirstName());
    user.setLastName(user.getLastName());

    userResource.update(user);
}

@shanmukakondaveti
Copy link

thanks, so first we need to write code to connect keycloak using builder() then after this we write the code you sent right?

@danushka-eranga
Copy link

thanks, so first we need to write code to connect keycloak using builder() then after this we write the code you sent right?

Yes

@configuration
public class KeycloakAdminClientConfig {

@Value("${keycloak.credentials.secret}")
private String secretKey;
@Value("${keycloak.resource}")
private String clientId;
@Value("${keycloak.auth-server-url}")
private String authUrl;
@Value("${keycloak.realm}")
private String realm;

@Bean
public Keycloak keycloak() {
    return KeycloakBuilder.builder()
            .grantType(CLIENT_CREDENTIALS)
            .serverUrl(authUrl)
            .realm(realm)
            .clientId(clientId)
            .clientSecret(secretKey)
            .build();
}

}

Then you can Autowired Keycloak in your class and use it

@shanmukakondaveti
Copy link

thank you

@shanmukakondaveti
Copy link

i am getting error in this line,,
ClientRepresentation app1Client =realmResource.clients().findByClientId("web_app").get(0);

my client is "web-app" ,so i placed "web-ap" and what is that 0, i dont know,can anyone tell me how to get client

@rc-bandit4461
Copy link

rc-bandit4461 commented Jun 21, 2021

i am getting error in this line,,
ClientRepresentation app1Client =realmResource.clients().findByClientId("web_app").get(0);

my client is "web-app" ,so i placed "web-ap" and what is that 0, i dont know,can anyone tell me how to get client

This is what you are looking for. The command realmResource.clients().findByClientId("web_app") is doing exactly what's in the picture below
image
You can see that it returns a JSON Array, which means the method findByClientId should return a list, hence the get(index).

the endpoint is http://<keycloakIP:KeycloakPort>/auth/admin/realms/<your realm>/clients?clientId=<your client ID>

Source: Keycloak REST API#Get Clients

Possible causes of the issue is there is the list returned is empty, test with the API so you can see whats really going on.

@drnow4u
Copy link

drnow4u commented Jun 3, 2022

Hi,
Thank you for helpful description and comments.
Do you know how to assign Service Account Roles with KeycloakBuilder? I would like to use it for tests.

image

@drnow4u
Copy link

drnow4u commented Jun 3, 2022

This solution Keycloak: Add Client Roles to Service Account Roles with Java API client is working for me. Where platform-administration is a client to update Service Account Roles.

@kashifJawed90
Copy link

I'm getting error on creating keycloakAdmin :

keycloakClient = KeycloakBuilder.builder() // .serverUrl(KC_ADMIN_CLIENT_SERVER_URL) // .realm(KC_ADMIN_CLIENT_REALM) // .grantType(OAuth2Constants.CLIENT_CREDENTIALS) // .clientId(KC_ADMIN_CLIENT_ID) // .clientSecret(KC_ADMIN_CLIENT_SECRET) // .resteasyClient(new ResteasyClientBuilder().connectionPoolSize(10).build()) .build();
POM.xml
<dependency> <artifactId>keycloak-admin-client</artifactId> <groupId>org.keycloak</groupId> <version>${keycloak.version}</version> </dependency>

java.lang.NoClassDefFoundError: org/keycloak/admin/client/KeycloakBuilder
at com.iotech.intellija.common.KeyCloakImpl.KeycloakAdminClientImpl.lambda$init$0(KeycloakAdminClientImpl.java:56)
at io.reactivex.internal.operators.completable.CompletableFromCallable.subscribeActual(CompletableFromCallable.java:36)
at io.reactivex.Completable.subscribe(Completable.java:2302)
at io.reactivex.internal.operators.completable.CompletablePeek.subscribeActual(CompletablePeek.java:51)
at io.reactivex.Completable.subscribe(Completable.java:2302)
at io.reactivex.internal.operators.completable.CompletableAndThenCompletable$SourceObserver.onComplete(CompletableAndThenCompletable.java:67)
at io.reactivex.internal.operators.completable.CompletableAndThenCompletable$NextObserver.onComplete(CompletableAndThenCompletable.java:99)
at io.reactivex.internal.operators.completable.CompletablePeek$CompletableObserverImplementation.onComplete(CompletablePeek.java:115)
at io.reactivex.internal.operators.completable.CompletablePeek$CompletableObserverImplementation.onComplete(CompletablePeek.java:115)
at io.reactivex.internal.operators.completable.CompletablePeek$CompletableObserverImplementation.onComplete(CompletablePeek.java:115)
at io.reactivex.internal.operators.completable.CompletablePeek$CompletableObserverImplementation.onComplete(CompletablePeek.java:115)
at io.reactivex.internal.operators.completable.CompletableAndThenCompletable$NextObserver.onComplete(CompletableAndThenCompletable.java:99)
at io.vertx.reactivex.impl.AsyncResultCompletable.lambda$subscribeActual$0(AsyncResultCompletable.java:48)
at io.vertx.core.impl.future.FutureImpl$3.onSuccess(FutureImpl.java:141)
at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:60)
at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:211)
at io.vertx.core.impl.future.PromiseImpl.tryComplete(PromiseImpl.java:23)
at io.vertx.core.Promise.tryComplete(Promise.java:121)
at io.vertx.core.Promise.complete(Promise.java:77)
at io.vertx.rabbitmq.impl.RabbitMQClientImpl.lambda$tryConnect$37(RabbitMQClientImpl.java:744)
at io.vertx.core.impl.future.FutureImpl$1.onSuccess(FutureImpl.java:91)
at io.vertx.core.impl.future.FutureImpl$ListenerArray.onSuccess(FutureImpl.java:262)
at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:60)
at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:211)
at io.vertx.core.impl.future.PromiseImpl.tryComplete(PromiseImpl.java:23)
at io.vertx.core.impl.future.PromiseImpl.onSuccess(PromiseImpl.java:49)
at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:60)
at io.vertx.core.impl.future.FutureImpl.addListener(FutureImpl.java:196)
at io.vertx.core.impl.future.PromiseImpl.addListener(PromiseImpl.java:23)
at io.vertx.core.impl.future.FutureImpl.onComplete(FutureImpl.java:164)
at io.vertx.core.impl.future.PromiseImpl.onComplete(PromiseImpl.java:23)
at io.vertx.rabbitmq.impl.RabbitMQClientImpl.lambda$tryConnect$36(RabbitMQClientImpl.java:738)
at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:76)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:750)
Caused by: java.lang.ClassNotFoundException: org.keycloak.admin.client.KeycloakBuilder
at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
... 40 common frames omitted

@shanuchauhan94
Copy link

shanuchauhan94 commented Feb 28, 2023

RoleRepresentation userRealmRole = new RoleRepresentation();
if (region.equalsIgnoreCase("india")) {
userRealmRole = realmResource.roles().get("user-ind").toRepresentation();
} else if (region.equalsIgnoreCase("us")) {
userRealmRole = realmResource.roles().get("user-us").toRepresentation();
}
UserResource userResource = usersResource.get(userId);
// Assign realm role 'user-ind' to user
userResource.roles().realmLevel().add(Collections.singletonList(userRealmRole));

    // Get client level role (requires view-clients role)
    List<ClientRepresentation> clientRepresentation = realmResource.clients().findByClientId(provider.CLIENT_ID);
    clientRepresentation.forEach(cr -> {
        RoleRepresentation roleRepresentation = realmResource.clients().get(cr.getId()).roles().get("USER").toRepresentation();
        userResource.roles().clientLevel(cr.getId()).add(List.of(roleRepresentation));
    });
    // Send password reset E-Mail
    usersResource.get(userId).executeActionsEmail(List.of("UPDATE_PASSWORD"));

in order to access these functionality you have to map user with few addition role as:
manage-realm
manage-users
manage-clients

@gilamarko
Copy link

Hello! First of all thanks for the provided code, I have a question, is there any official documentation of how to use the
org.keycloak:keycloak-admin-client ??

For sure your example is great but if I hadn't found this, it would be a nightmare to learn how to use it on the fly.

@ghilainm
Copy link

@thomasdarimont Isn't it possible to do it in one shot? Assign password and roles when creating the user? I tried but it seems not to work...

@AndreaNicola
Copy link

AndreaNicola commented Jan 30, 2024 via email

@ghilainm
Copy link

@AndreaNicola Credentials seem to work for me!

@hyenicil
Copy link

Hello, how do I use keycloak for its new versions?

@maj2c
Copy link

maj2c commented Apr 23, 2024

If you still getting "HTTP 400 Bad request" error after following the tips and hints in this ticket or it suddenly stopped working, make sure the user account you are using does not have unresolved required actions such as verify email, fill in first name and last name etc. because you can't invoke direct grant if there are unresolved required actions!

I am using the latest version (24.0.3) at the time of writing this comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment