Keycloak Missing form parameter: grant_type

39,261

Solution 1

You should send your data in a POST request with Content-Type header value set to application/x-www-form-urlencoded, not json.

Solution 2

With Curl

curl -X POST \
http://localhost:8080/auth/realms/api-gateway/protocol/openid-connect/token \
-H 'Accept: */*' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'Content-Length: 73' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Cookie: JSESSIONID=F8CD240FF046572F864DC37148E51128.a139df207ece;   JSESSIONID=65D31B82F8C5FCAA5B1577DA03B4647C' \
-H 'Host: localhost:8080' \
-H 'Postman-Token: debc4f90-f555-4769-b392-c1130726a027,d5087d9f-9253-48bd-bb71-fda1d4558e4d' \
-H 'User-Agent: PostmanRuntime/7.15.2' \
-H 'cache-control: no-cache' \
-d 'grant_type=password&client_id=api-gateway&username=admin&password=temp123'

By Postman (Select x-www-form-urlencoded option for parameters)

enter image description here

Solution 3

For those having problems with curl the curl command is as follows

curl -d "client_secret=<client-secret>" -d "client_id=<client-id>" -d "username=<username>" -d "password=<password>" -d "grant_type=password" "http://localhost:8080/auth/realms/<realm-name>/protocol/openid-connect/token"

The curl command works without the Content-Type header.

Solution 4

For those who landed here from a search looking for JavaScript solution.

Here is an example when exchanging code for access_token with keycloak authority using axios.

Sending the request:


const params = new URLSearchParams({

    grant_type: 'authorization_code',
    client_id: 'client-id-here',
    code: 'code-from-previous-redirect',
    redirect_uri: location.protocol + '//' + location.host

});

axios({

    method: 'post',
    url: 'https://my-keycloak.authority/token',
    data: params.toString(),
    config: {
        headers: {'Content-Type': 'application/x-www-form-urlencoded'}
    }

}).then(response => {

    console.log(response.data);

}).catch(error => {

    console.error(error);

});

You are required to send a POST request with the parameters as a URL encoded string in the request body.

FormData object does not work.

Share:
39,261
Borislav Stoilov
Author by

Borislav Stoilov

Passionate about software technologies

Updated on July 11, 2022

Comments

  • Borislav Stoilov
    Borislav Stoilov almost 2 years

    I have keycloak standalone running on my local machine.

    I created new realm called 'spring-test', then new client called 'login-app'

    According to the rest documentation:

    POST: http://localhost:8080/auth/realms/spring-test/protocol/openid-connect/token
    
    {
        "client_id": "login-app",
        "username": "user123",
        "password": "pass123",
        "grant_type": "password"
    }
    

    should give me the jwt token but I get bad request with response

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

    I am assuming that something is missing in my configuration.

    EDIT: I was using json body but it should be application/x-www-form-urlencoded: the following body works:

    token_type_hint:access_token&token:{token}&client_id:{client_id}&client_secret:{client_secret}
    
  • Ognjen Mišić
    Ognjen Mišić about 5 years
    I'm still having the same issue, even if i set the content type to be urlencoded: curl -d '{"grant_type": "password", "username": "user", "password": "pass", "client_id": "login-app"}' -H "Content-Type: application/x-www-form-urlencoded" -X POST "localhost:8082/auth/realms/ina-dev/protocol/openid-connect/‌​…" {"error":"invalid_request","error_description":"Missing form parameter: grant_type"}
  • ipave
    ipave about 5 years
    because you send json data, you should use -d "param1=value1&param2=value2" syntaxis
  • Avión
    Avión about 5 years
    This is not working. How do you set that -d stuff in postman, @ipave?
  • ipave
    ipave about 5 years
  • masterxilo
    masterxilo almost 5 years
    Thanks, I was sending "multipart/form-data; boundary=--------------------------616846104444017186133807"
  • aswzen
    aswzen almost 4 years
    don't forget to put client_secret
  • Syam Sankar
    Syam Sankar over 3 years
    There is an easy way to get token without using query string. const config = { headers: {'Content-Type': 'application/x-www-form-urlencoded'} }; const formParameter = client_id=KEYCLOAK_CLIENT_ID&client_secret=KEYCLOAK_CLIENT_S‌​ECRET&grant_type=KEY‌​CLOAK_API_GRANT_TYPE‌​; axios.post(REQUEST_URL,formParameter,config);
  • Scratte
    Scratte about 3 years
    Pavan J posted an Answer saying "Thanks @marc for the solution and it works! I have been looking for this solution in quite a number of forums. PS: There's a typo in grant_type: 'authorization_code', (closing quote missing)"
  • Sudarshan
    Sudarshan about 2 years
  • Jonathan Beadle
    Jonathan Beadle about 2 years
    Since querystring is depricated as @sudarshan pointed out, we can use URLSearchParams instead. In this code snippet we can substitute new URLSearchParams(params) for queryString.stringify(params). URLSearchParams should be supported in newer versions of node and the browser. If your version of node doesn't have support for it we can use a polyfill