Search code examples
spring-bootkeycloak

Adding user to keycloak using Spring Boot


I am using keycloak admin for user login and user creation. I was able to login a user thru my spring boot application and return a AccessTokenResponse. For user creation I am getting a 403 response. I followed this tutorial and the UI is different now for Keycloak:21.1.0.

What I need to do is to add the manage-users to my client the old UI looks like this: enter image description here

The new UI looks like this: enter image description here

CODE:

Here's my KeycloackConfig:

import org.keycloak.OAuth2Constants;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@KeycloakConfiguration
public class KeycloakConfig {

  @Value("${keycloak.auth-server-url}")
  public String serverURL;
  @Value("${keycloak.realm}")
  public String realm;
  @Value("${keycloak.resource}")
  public String clientID;
  @Value("${keycloak.credentials.secret}")
  public String clientSecret;

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

  @Bean
  public KeycloakConfigResolver keycloakConfigResolver() {
    return new KeycloakSpringBootConfigResolver();
  }
}

Here's my KeycloakService:

import lombok.RequiredArgsConstructor;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.ws.rs.BadRequestException;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.core.Response;
import java.util.Collections;

@Service
@RequiredArgsConstructor
public class KeycloakService {
  @Value("${keycloak.auth-server-url}")
  private String serverURL;
  @Value("${keycloak.realm}")
  private String realm;
  @Value("${keycloak.resource}")
  private String clientID;
  @Value("${keycloak.credentials.secret}")
  private String clientSecret;

  private final Keycloak keycloakAdminClient;

  public void registerExisting(SignUpRequest request) {
    this.createKeycloakUser(request);
  }


  public AccessTokenResponse login(LoginRequest request) {
    try (Keycloak keycloak = this.keycloakCredentialBuilder(request)) {
      return keycloak.tokenManager().getAccessToken();
    } catch (NotAuthorizedException e) {
      throw new KeycloakUnauthorizedException(e.getMessage());
    } catch (BadRequestException e) {
      throw new KeycloakBadRequestException(e.getMessage());
    }
  }

  public void createKeycloakUser(SignUpRequest request) {
    UsersResource usersResource = this.keycloakAdminClient.realm(this.realm).users();
    CredentialRepresentation credentialRepresentation = createPasswordCredentials(request.getPassword());

    UserRepresentation user = new UserRepresentation();
    user.setUsername(request.getUsername());
    user.setEmail(request.getEmail());
    user.setFirstName(request.getFirstName());
    user.setLastName(request.getLastName());
    user.singleAttribute("phoneNumber",request.getPhoneNumber());
    user.setCredentials(Collections.singletonList(credentialRepresentation));


    try (Response response = usersResource.create(user)) {
      if(response.getStatus() == 201) {
        System.out.println("Created");
      } else {
        System.out.println(response.getStatus());
      }
    } catch (Exception e) {
      System.out.println(e.getMessage());
    }
  }

  private Keycloak keycloakAdminBuilder() {
    return KeycloakBuilder.builder()
      .realm(realm)
      .serverUrl(serverURL)
      .clientId(clientID)
      .clientSecret(clientSecret)
      .grantType(OAuth2Constants.CLIENT_CREDENTIALS)
      .build();
  }

  private Keycloak keycloakCredentialBuilder(LoginRequest request) {
    return KeycloakBuilder.builder()
      .realm(this.realm)
      .serverUrl(this.serverURL)
      .clientId(this.clientID)
      .clientSecret(this.clientSecret)
      .username(request.getUsername())
      .password(request.getPassword())
      .build();
  }

  private CredentialRepresentation createPasswordCredentials(String password) {
    CredentialRepresentation passwordCredentials = new CredentialRepresentation();
    passwordCredentials.setTemporary(false);
    passwordCredentials.setType(CredentialRepresentation.PASSWORD);
    passwordCredentials.setValue(password);
    return passwordCredentials;
  }
}

QUESTIONS

  1. I checked my clients on my realm and there is a manage-users in my real-management. Do I need to add another role in my client?
  2. Is my code right? Or do I need to add or modify something?

Solution

  • The code was right. The problem was in configuration.

    Here is the steps of how I resolved this:

    1. Under Realm Roles > Create a new Role > Add a name for the role > Click Save
    2. Select that role you just created, then click Action on the upper right side. enter image description here
    3. Click Add Associated Role > Click Filter By Clients > Select the manage-users under realm-management.
    4. Under Client > Select your client > Click Service Account Roles > Add the role you just created earlier.

    This should respond 201 when you create a user. Took me days to figure this out. Hope that this post would help someone.