javaspring-bootrestmicroserviceskeycloak

Error registering user in Keycloak: username required while using Keycloak Admin Client API


Problem:

When I try to register a user by sending a POST request to the /register endpoint with a payload like this:

{
    "username": "asas",
    "email": "asas@gmail.com",
    "password": "asas"
}

The system fails, and the following error is logged:

2025-02-05T15:36:28.299+07:00  INFO 42339 --- [auth-service] [nio-8081-exec-1] o.f.user.controller.AuthController       : Received registration request for username: asas
2025-02-05T15:36:28.299+07:00  INFO 42339 --- [auth-service] [nio-8081-exec-1] o.f.user.listener.AuthEventListener      : Processing user registration for username: asas
2025-02-05T15:36:28.300+07:00 ERROR 42339 --- [auth-service] [nio-8081-exec-1] o.f.user.listener.AuthEventListener      : Error registering user in Keycloak: username required

What I’ve Tried:

Code

Configuration:

keycloak:
  realm: <your-realm-name>
  auth-server-url: http://localhost:9090/
  resource: <your-resource-name>
  credentials:
    client-id: <your-client-id>
    secret: <your-secret>
  use-resource-role-mappings: true

AuthController:

@RestController
@RequestMapping("/api/v1/auth")
@RequiredArgsConstructor
public class AuthController {

    private final AuthEventListener userEventListener;
    private static final Logger logger = LoggerFactory.getLogger(AuthController.class);

    @PostMapping("/register")
    public ResponseEntity<?> register(@RequestBody UserRegisteredEvent event) {
        logger.info("Received registration request for username: {}", event.getUsername());
        return userEventListener.handleUserRegistration(event);
    }

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody UserLoginEvent event) {
        return userEventListener.handleUserLogin(event);
    }
}

AuthEventListener:

@Service
@RequiredArgsConstructor
public class AuthEventListener {

    private final KafkaTemplate<String, UserRegisteredEvent> userRegisteredTemplate;
    private final AuthService authService;

    private static final Logger logger = Logger.getLogger(AuthEventListener.class.getName());

    @KafkaListener(topics = "user-registration", groupId = "auth-service")
    public ResponseEntity<?> handleUserRegistration(UserRegisteredEvent event) {
        logger.info("Processing user registration for username: " + event.getUsername());
        try {
            authService.registerUser(event.getUsername(), event.getEmail(), event.getPassword());
            userRegisteredTemplate.send("user-registered", event);
            logger.info("User successfully registered in Keycloak: " + event.getUsername());
        } catch (Exception e) {
            logger.severe("Error registering user in Keycloak: " + e.getMessage());
        }
        return ResponseEntity.ok().build();
    }
}

AuthService:

@Service
@RequiredArgsConstructor
public class AuthService {

    @Value("${keycloak.auth-server-url}")
    private String keycloakAuthServerUrl;

    @Value("${keycloak.realm}")
    private String keycloakRealm;

    @Value("${keycloak.credentials.client-id}")
    private String keycloakClientId;

    @Value("${keycloak.credentials.secret}")
    private String keycloakClientSecret;

    private static final Logger logger = Logger.getLogger(AuthService.class.getName());

    private Keycloak getAdminKeycloakInstance() {
        return KeycloakBuilder.builder()
                .serverUrl(keycloakAuthServerUrl)
                .realm(keycloakRealm)
                .clientId(keycloakClientId)
                .clientSecret(keycloakClientSecret)
                .build();
    }

    public void registerUser(String username, String email, String password) {
        Keycloak keycloak = getAdminKeycloakInstance();
        RealmResource realmResource = keycloak.realm(keycloakRealm);
        UsersResource usersResource = realmResource.users();

        UserRepresentation user = new UserRepresentation();
        user.setUsername(username);
        user.setEmail(email);
        user.setEnabled(true);

        Response response = usersResource.create(user);
        if (response.getStatus() != 201) {
            throw new RuntimeException("Failed to create user in Keycloak: " + response.getStatusInfo());
        }
        String userId = response.getLocation().getPath().replaceAll(".*/([^/]+)$", "$1");

        CredentialRepresentation credential = new CredentialRepresentation();
        credential.setTemporary(false);
        credential.setType(CredentialRepresentation.PASSWORD);
        credential.setValue(password);
        keycloak.realm(keycloakRealm).users().get(userId).resetPassword(credential);

        RoleRepresentation userRole = realmResource.roles().get("user").toRepresentation();
        keycloak.realm(keycloakRealm).users().get(userId)
                .roles().realmLevel().add(Collections.singletonList(userRole));

        logger.info("User successfully registered in Keycloak: " + username);
    }
}

Solution

  • Educated guess here:

    The username that is referred to as missing is that of the admin account expected by Keycloak, not the user you try to add.

    From your config, it seems like you want to use client credentials for admin authentication, but you don't specify it. I think this leads to Keycloak falling back to the default of requiring an admin username and password, which you do not supply.

    Try adding this line in your KeycloakBuilder:

    .grantType(OAuth2Constants.CLIENT_CREDENTIALS)