Search code examples
passwordshttpclientkeycloakjava-11

Java 11 HttpClient - Missing form parameter: grant_type


I'm trying to get an access token from Keycloack server via HttpClient of Java 11. But I keep getting an error:

{
    "error":"invalid_request",
    "error_description":"Missing form parameter: grant_type"
}

By the way, with postman, I can get the token. What I'm doing in my code is:

        Map<String, String> values = new HashMap<>() {{
            put("username", username);
            put ("password", password);
            put("grant_type", "password");
        }};

        ObjectMapper objectMapper = new ObjectMapper();
        String requestBody = objectMapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(values);

        HttpRequest request=HttpRequest.newBuilder()
                .uri(URI.create(tokenEndpoint))
                .setHeader("client_id", clientId)
                .setHeader("client_secret", clientSecret)
                .setHeader("content-type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();



        HttpClient.newHttpClient()
                .sendAsync(request, HttpResponse.BodyHandlers.ofString())
                .thenApply(HttpResponse::body)
                .thenAccept(System.out::println);

        /*
        //Tried also
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
        */

What am I doing wrong or missing?

Keycloak Missing form parameter: grant_type not worked.


Solution

  • This is how we done login:

    MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
    requestParams.add("client_id", keycloakProperties.getResource());
    requestParams.add("username", username);
    requestParams.add("password", password);
    requestParams.add("grant_type", "password");
    requestParams.add("client_secret", String.valueOf(keycloakProperties.getCredentials().get("secret")));
    requestParams.add("scope", "openid");
    
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    
    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(requestParams, headers);
    
    String url = keycloakProperties.getAuthServerUrl() + "/realms/" + keycloakProperties.getRealm() + "/protocol/openid-connect/token";
    
    AccessTokenResponse keycloakAccessToken = getAccessTokenResponse(request, url);
    
    
    // sometimes SSL handshake was failing, so catching error and trying again :)
    private AccessTokenResponse getAccessTokenResponse(HttpEntity<MultiValueMap<String, String>> request, String url) {
        try {
            ResponseEntity<AccessTokenResponse> response = restTemplate.postForEntity(url, request, AccessTokenResponse.class);
            return response.getBody();
        } catch (ResourceAccessException e) {
            log.error("KeyCloak getAccessTokenResponse: " + e.getMessage());
            try {
                ResponseEntity<AccessTokenResponse> response = restTemplate.postForEntity(url, request, AccessTokenResponse.class);
                return response.getBody();
            } catch (Exception ex) {
                throw ex;
            }
        } catch (Exception e) {
            throw e;
        }
    }