1

I am trying to convert a curl request, which is giving me a token into Spring's Resttemplate post request, but I am getting 403 - bad request

My Curl Request

curl -d "grant_type=client_credentials&client_id=nu5yzeth9tektzf5egxuntp7&client_secret=uP2Xvr6SCKYgXgxxJsv2QkUG" 
  -H "Content-Type: application/x-www-form-urlencoded" 
  -X POST https://cloudsso.example.com/as/token.oauth2

Curl Response:

{"access_token":"HVURQ845OPJqs8UpOlef5m2ZCNwR","token_type":"Bearer","expires_in":3599}

Now, Here is my Java code to implement above curl post request

RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));

MultiValueMap<String, String> bodyParamMap = new LinkedMultiValueMap<String, String>();
bodyParamMap.add("grant_type", "client_credentials");
bodyParamMap.add("client_id", "nu5yzeth9tektzf5egxuntp7");
bodyParamMap.add("client_secret", "uP2Xvr6SCKYgXgxxJsv2QkUG");

entity = new HttpEntity<>(reqBodyData, bodyParamMap);

restTemplate.postForEntity(url, entity, TokenDTO.class)

Resttemplate call response:

2019-12-04 11:10:16,483[0;39m [39mDEBUG[0;39m [[34mrestartedMain[0;39m] [33morg.springframework.core.log.CompositeLog[0;39m: Accept=[application/json, application/*+json]
[30m2019-12-04 11:10:16,484[0;39m [39mDEBUG[0;39m [[34mrestartedMain[0;39m] [33morg.springframework.core.log.CompositeLog[0;39m: Writing [{"grant_type":["client_credentials"],"client_id":["nu5yzeth9tektzf5egxuntp7"],"client_secret":["uP2Xvr6SCKYgXgxxJsv2QkUG"]}] with org.springframework.http.converter.StringHttpMessageConverter
[30m2019-12-04 11:10:17,976[0;39m [39mDEBUG[0;39m [[34mrestartedMain[0;39m] [33morg.springframework.core.log.CompositeLog[0;39m: Response 400 BAD_REQUEST
[30m2019-12-04 11:10:17,981[0;39m [34mINFO [0;39m [[34mrestartedMain[0;39m] [33mcom.ibm.ciscoApiIntegration.service.impl.CiscoAPIServiceImpl[0;39m: e::: 400 Bad Request

How can make the above curl request in RestTemplate working?

Note: https://cloudsso.example.com/as/token.oauth2 it's little modified for the question.

M. Deinum
  • 94,295
  • 20
  • 185
  • 191
vicky
  • 746
  • 2
  • 18
  • 48
  • Does this answer your question? [Spring RestTemplate POST Request with URL encoded data](https://stackoverflow.com/questions/49127240/spring-resttemplate-post-request-with-url-encoded-data) – Shivam Puri Dec 04 '19 at 06:30
  • 1
    My recommendation would be _not to do that at all_ and use an OAuth2 client that already understands this. There are several available, including one for Spring that integrates with RestTemplate. – chrylis -cautiouslyoptimistic- Dec 04 '19 at 07:11
  • 1
    You need to set the content type properly on the `HttpHeaders` and your `HttpEntity` is constructed wrongly (you aren't passing the headers). – M. Deinum Dec 04 '19 at 07:50
  • @[chrylis-onstrike]- I was trying oauth2 client but wasn't able to find a working reference code, so I tried this, if you have any reference, please share it with me. – vicky Dec 04 '19 at 16:07

3 Answers3

2

If you take a look at the documentation for HttpEntity you will see that you are using the wrong constructor.

entity = new HttpEntity<>(reqBodyData, bodyParamMap);

You are passing the arguments you want to use as the body (bodyParamMap) as headers (as the second argument is the headers to be used for the request). In fact you aren't even using the HttpHeaders for the request as you aren't passing them to the HttpEntity. I'm not sure what the reqBodyData is but probably a toString of the bodyParamMap.

What you should have been doing is the following

entity = new HttpEntity<>(bodyParamMap, headers);

As HttpHeaders impements MultiValueMap you can directly use them in the constructor. You also want to pass the bodyParamMap as is.

NOTE: I would also suggest to explictly set the Content-Type on the HttpHeaders so you are sure what is being send.

headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

Thus the total resulting code should look like

RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

MultiValueMap<String, String> bodyParamMap = new LinkedMultiValueMap<>();
bodyParamMap.add("grant_type", "client_credentials");
bodyParamMap.add("client_id", "nu5yzeth9tektzf5egxuntp7");
bodyParamMap.add("client_secret", "uP2Xvr6SCKYgXgxxJsv2QkUG");

entity = new HttpEntity<>(bodyParamMap, headers);

restTemplate.postForEntity(url, entity, TokenDTO.class)

NOTE: You shouldn't be constructing a single use RestTemplate but you rather want to configure that once and inject that into your class.

M. Deinum
  • 94,295
  • 20
  • 185
  • 191
  • Thank you @M. Deinum, I didn't know a few things, you share with me. Although, I solved my problem, before your answer, but your one is in more detail and have some points, which can really help others. – vicky Dec 12 '19 at 18:26
1

As suggested by post https://stackoverflow.com/a/49127760/11226302

You should set the request content type in header as; headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

Hope this helps!

Shivam Puri
  • 915
  • 7
  • 20
1

I have just solved the issue:

I had this in this

// wrong
//private HttpEntity<String> entity;

I changed it to this:

private MultiValueMap<String, String> parametersMap;

and changed it

// not working
entity = new HttpEntity<>(reqBodyData, bodyParamMap);

to this

// working
entity = new HttpEntity<>(bodyParamMap, headers);

Now it's working perfectly fine.

response:

2019-12-04 11:52:46,503 DEBUG [restartedMain] org.springframework.core.log.CompositeLog: HTTP POST https://cloudsso.example.com/as/token.oauth2
2019-12-04 11:52:46,521 DEBUG [restartedMain] org.springframework.core.log.CompositeLog: Accept=[application/json, application/*+json]
2019-12-04 11:52:46,522 DEBUG [restartedMain] org.springframework.core.log.CompositeLog: Writing [{grant_type=[client_credentials], client_id=[nu5yzeth9tektzf5egxuntp7], client_secret=[uP2Xvr6SCKYgXgxxJsv2QkUG]}] with org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
2019-12-04 11:52:47,831 DEBUG [restartedMain] org.springframework.core.log.CompositeLog: Response 200 OK

Note: in my case, adding or disabling this value, isn't making any difference, i am getting the auth token anyway.

//headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
vicky
  • 746
  • 2
  • 18
  • 48
  • 1
    The problem was that you where sending the body as headers, and not sure what `reqBodyData` was. But due to this it was selection the wrong message encoder. Nonentheless you are propably better of with explicitly setting the content-type to be sure (you also did that more-or-less with `-d` using curl ). – M. Deinum Dec 04 '19 at 07:55