Why does this REST request work from every client except Talend API tester - api

This is an example of a REST POST request that works everywhere except Talend API tester. It give a 500 error.
Here is how I set the request up in my applications.
URLConnection connection = new URL("https://" + authHost + "/connect/token").openConnection();
logger.info("Connection oppened");
// message contains the form data: key=value&key=value&key=value
String message = "password=" + password + "&grant_type=password&username=" + username +
"&client_id=foolid&scope=mouthwash";
logger.info(message);
// Setting header fields.
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Accept", "application/json");
connection.getOutputStream().write(message.getBytes("UTF-8"));
Here is a working example in Postman
POST /connect/token HTTP/1.1
Host: identityserver.uat.example.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Cookie: ARRAffinity=6a37d2ecf3441e27913cb832c4b767c68cad0e45c8806b3c5344d1b52d57f67a; ARRAffinitySameSite=6a37d2ecf3441e27913cb832c4b767c68cad0e45c8806b3c5344d1b52d57f67a
Content-Length: 137
password=secret&grant_type=password&username=fool&client_id=foolid&scope=mouthwash
And here is what Talend say it sends, which gets the 500 error -- which I understand comes from the server.
POST /connect/token HTTP/1.1
Accept: application/json
Content-Length: 137
Content-Type: application/x-www-form-urlencoded
Host: identityserver.uat.example.com
password=secret&grant_type=password&username=fool&client_id=foolid&scope=mouthwash
What's happening here?

Related

Content-Type header property value quoting doesn't work with third-party server

Is it correct to quote the boundary property value of Content-Type header?
I have sent an http-request with two files to a third-party server and get the following response:
Boundary '--"38b14895-fd44-4acc-8287-9f0378691da2"' not found in message body
because RestSharp quotes the boundary value, but the server doesn't unquote it. I can neither change the third-party server nor customize RestSharp header quoting.
What is the problem? Does the http spec allow escaped strings in header property values? I've read the spec, but haven't found a place where this would be explicitly defined.
I create the RestRequest something like this:
private RestRequest CreateRequest( ... )
{
var request_url = $"url?param=value";
var request = new RestRequest( request_url, Method.Post );
request.AddFile( "file1", ..., "file1", "application/xml" );
request.AddFile( "file2", ..., "file2", "audio/x-wav" );
request.AddHeader( "Content-Type", "multipart/form-data" );
return request;
}
and get the following HTTP-request:
POST /url?param=value
Host: 192.168.1.1:80
Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml
User-Agent: RestSharp/108.0.1.0
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary="38b14895-fd44-4acc-8287-9f0378691da2"
Content-Length: 227841
--38b14895-fd44-4acc-8287-9f0378691da2
Content-Type: application/xml
Content-Disposition: form-data; name="file1"; filename="file1"
[data]
--38b14895-fd44-4acc-8287-9f0378691da2
Content-Type: audio/x-wav
Content-Disposition: form-data; name="file2"; filename="file2"
[data]
--38b14895-fd44-4acc-8287-9f0378691da2--
Okay so I have just been dealing with a very similar issue. I found this GitHub Issue which gives some good context into the actual issue that is occurring here but I have also found a fix.
Firstly, you shouldn't manually add the "Content-Type" header. RestSharp will do this for you since you are using the AddFile() method.
I am assuming you are using the latest version of RestSharp, if so you can set the request.OnBeforeRequest property of the RestRequest to handle this and strip out the double quotes around the boundary before the request is sent:
request.OnBeforeRequest = (http) =>
{
var boundary = http.Content.Headers.ContentType.Parameters.First(o => o.Name == "boundary");
boundary.Value = boundary.Value.Replace("\"", String.Empty);
return default;
};
Hope this helps!

Get shopify analytics token programmatically

How do you get the token needed to make a request to the Shopify analytics API?
For example:
POST https://analytics.shopify.com/queries?beta=true
REQUEST BODY:
token: HOW_DO_I_GET_THIS?
q[]: SHOW+total_visitors+AS+%22total_visitors...
source: shopify-reports
I've tried using OAuth, but it seems to be a different token entirely.
You have to request Shopify Core GraphQL to get analyticsToken.
POST /admin/internal/web/graphql/core HTTP/1.1
Host: [[STORE_NAME]].myshopify.com
Accept: application/json
Accept-Language: en-CA,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
content-type: application/json
X-CSRF-Token: [[CSRF_TOKEN]]
Origin: https://[[STORE_NAME]].myshopify.com
Connection: close
Cookie: [[COOKIE]]
{ "query": "{ shop { analyticsToken } }" }
Since the request requires CSRF Token & Cookie, it's not programmatic at all.
For additional information please check the Examples for Testing in the Shopify Admin page.

How to send request POST message to API server in flutter?

I'm using NAVER API to detect faces, so I have to send POST message to API server. The format of message is like below.
[HTTP Request Header]
POST /v1/vision/face HTTP/1.1
Host: openapi.naver.com
Content-Type: multipart/form-data; boundary={boundary-text}
X-Naver-Client-Id: {Client ID}
X-Naver-Client-Secret: {Client Secret}
Content-Length: 96703
--{boundary-text}
Content-Disposition: form-data; name="image"; filename="test.jpg"
Content-Type: image/jpeg
{image binary data}
--{boundary-text}--
After I checked format, I wrote using MultipartRequest and MultipartFile.
Future<void> getFaceData() async {
final Uri url = Uri.parse('https://openapi.naver.com/v1/vision/face');
final request = http.MultipartRequest('POST',url);
request.fields['X-Naver-Client-Id'] = 'client key(I added real value)';
request.fields['X-Naver-Client-Secret'] = 'client secret(I added real value)';
request.files.add(await http.MultipartFile.fromPath(
'image',
_image.path,
contentType: MediaType('multipart','form-data')
));
http.StreamedResponse response = await request.send();
print(response.statusCode);
}
But this code gets 401 error which is UNAUTHORIZED. What is the problem? How can I fix it?
The X-Naver... values are HTTP headers, rather than form fields. Add them like this instead:
request.headers['X-Naver-Client-Id'] = 'client key(I added real value)';
request.headers['X-Naver-Client-Secret'] = 'client secret(I added real value)';

How to get Header Location value from a Fetch request in browser

From a ReactJS - Redux front app, I try to get the Location Header value of an REST API response.
When I Curl this :
curl -i -X POST -H "Authorization: Bearer MYTOKEN" https://url.company.com/api/v1.0/tasks/
I Have this answer :
HTTP/1.1 202 ACCEPTED
Server: nginx
Date: Fri, 12 Aug 2016 15:55:47 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Connection: keep-alive
Location: https://url.company.com/api/v1.0/tasks/status/idstatus
When I make a Fetch in ReactJS
var url = 'https://url.company.com/api/v1.0/tasks/'
fetch(url, {
method: 'post',
credentials: 'omit',
headers: {
'Authorization': `Bearer ${token}`
}
}
)
I don't have any Headers in the response object :
No header in Fetch request
I tried all the response.headers functions I've found in https://developer.mozilla.org/en-US/docs/Web/API/Headers :
response.headers.get('Location');
But well, as headers is empty, I have empty results.
Do you know why I can't get a proper Header object filled with the headers values ?
Thanks to John, I've found the answer.
I just had to put
Access-Control-Expose-Headers: Location
To my response headers and it worked, so now I can access Location value with :
response.headers.get('Location');
Thx John !
Besides to expose the Location Header in the server.
I just could access the location in the react application with:
response.headers.location;

Client credential grant type is not properly sent with Apache Oltu client library?

I tried to implement an OAuth client using OAuthClientRequest in Apache Oltu. And it seems to be that it is sending client credentials in the message body not in the Basic Auth headers according to the spec. I am not sure, I may have missed some thing in the code.
Code
OAuthClientRequest.tokenLocation("http://localhost:8081/token")
.setGrantType(GrantType.CLIENT_CREDENTIALS)
.setClientId(clientKey)
.setClientSecret(clientSecret)
.buildBodyMessage();
Request
POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.6.0_29
Host: 127.0.0.1:8081
Accept: text/html, image/gif, image/jpeg, *; q=.2, /; q=.2
Connection: keep-alive
Content-Length: 127
client_secret=f921854d-f70b-4180-9fdd-3a55032103cc&grant_type=client_credentials&client_id=3f3b4092-7576-4b26-8135-980db7864c2
You might want to change buildBodyMessage() with buildQueryMessage()
The OAuth2 Bearer Token specification defines three methods of sending bearer access tokens:
Authorization Request Header Field
Form-Encoded Body Parameter
URI Query Parameter
The method buildBodyMessage() will create a request with a Form-Encoded Body Parameter. You need to use buildHeaderMessage() instead, which is also the recommended method by the specification.
Recently, I've trying to find a OAuth2 java library to get "client_credential" type of accesstoken. And below is what I have for Apache Oltu, and it seems that it is working.
#Test
public void getAccessTokenViaApacheOltuOAuthClient() {
try{
OAuthClient client = new OAuthClient(new URLConnectionClient());
OAuthClientRequest request =
OAuthClientRequest.tokenLocation(TOKEN_REQUEST_URL)
.setGrantType(GrantType.CLIENT_CREDENTIALS)
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setScope(StringUtils.join(TEST_SCOPES, " ")) //if you have scope
.buildBodyMessage();
String token =
client.accessToken(request, "POST", OAuthJSONAccessTokenResponse.class)
.getAccessToken();
System.out.println(token);
assertTrue( token != null);
} catch (Exception e) {
e.printStackTrace();
}
}