Using https://mws.amazonservices.com/scratchpad/index.html, I am able to make a valid request to the MWS endpoint, the details of which look like this:
POST /Products/2011-10-01?AWSAccessKeyId=myAWSAccessKeyId
&Action=GetMatchingProductForId
&SellerId=mySellerId
&SignatureVersion=2
&Timestamp=2018-08-14T01%3A00%3A39Z
&Version=2011-10-01
&Signature=6xwEi3Mk9Ko9v9DyF9g6zA4%2Buggi7sZWTlUmNDxHTbQ%3D
&SignatureMethod=HmacSHA256
&MarketplaceId=ATVPDKIKX0DER
&IdType=UPC
&IdList.Id.1=043171884536 HTTP/1.1
Host: mws.amazonservices.com
x-amazon-user-agent: AmazonJavascriptScratchpad/1.0 (Language=Javascript)
Content-Type: text/xml
How can I take this, and turn it into a valid URL that I can use to make a request from my app, i.e., using fetch or some other javascript implementation. I tried to take the info and make a URL like this:
https://mws.amazonservices.com/Products/2011-10-01?
AWSAccessKeyId=myAWSAccessKeyId
&Action=GetMatchingProductForId
&SellerId=mySellerId
&SignatureVersion=2
&Timestamp=2018-08-14T01%3A00%3A39Z
&Version=2011-10-01
&Signature=6xwEi3Mk9Ko9v9DyF9g6zA4%2Buggi7sZWTlUmNDxHTbQ%3D
&SignatureMethod=HmacSHA256
&MarketplaceId=ATVPDKIKX0DER
&IdType=UPC
&IdList.Id.1=043171884536
, to which I tried to send a POST request via postman, and I got this error:
<?xml version="1.0"?>
<ErrorResponse xmlns="https://mws.amazonservices.com/">
<Error>
<Type>Sender</Type>
<Code>InvalidParameterValue</Code>
<Message>Value 2
for parameter SignatureVersion is invalid.</Message>
</Error>
<RequestID>6ded1eed-eb92-4db6-9837-3453db0f8a77</RequestID>
</ErrorResponse>
How can I make a valid request to an MWS endpoint using javascript?
You could use npm module like superagent, axios or request.
const agent = require('superagent)
agent
.post('https://mws.amazonservices.com/Products/2011-10-01')
.query({
AWSAccessKeyId: myAWSAccessKeyId,
Action: GetMatchingProductForId,
SellerId: mySellerId,
SignatureVersion: 2,
Timestamp: 2018-08-14T01%3A00%3A39Z,
Version: 2011-10-01,
Signature: 6xwEi3Mk9Ko9v9DyF9g6zA4%2Buggi7sZWTlUmNDxHTbQ%3D,
SignatureMethod: HmacSHA256,
MarketplaceId: ATVPDKIKX0DER,
IdType: UPC,
IdList.Id.1: 043171884536
})
.then(res => {
console.log('here is the response');
console.log(res)
})
.catch(error => {
console.log('here is the error');
console.log(error);
})
I haven't written against AWS but are you sure that these parameters should be sent with the querystring. Usually with post, parameters are sent with the body?
The error you are recieving from Postman is telling you that you are reaching the server but something is wrong the with values that you are sending. For example: SignatureVersion should be 1 (or something).
I used node-fetch to make a valid request the MWS endpoint. You can look code as given below.
var param = {};
param['AWSAccessKeyId'] = 'xxxxxxxxxxxxx';
param['Action'] = 'GetMatchingProductForId';
param['MarketplaceId'] = 'xxxxxxxxxxxxx';
param['SellerId'] = 'xxxxxxxxxxxxx';
param['IdType'] = 'ISBN';
param['IdList.Id.1'] = 'xxxxxxxxxx';
param['ItemCondition'] = 'New';
param['SignatureMethod'] = 'HmacSHA256';
param['SignatureVersion'] = '2';
param['Timestamp'] = encodeURIComponent(new Date().toISOString());
param['Version'] = '2011-10-01';
secret = 'xxxxxxxxxxxxx';
var url = [];
for(var i in param){
url.push(i+"="+param[i])
}
url.sort();
var arr = url.join("&");
var sign = 'POST\n'+'mws.amazonservices.com\n'+'/Products/2011-10-01\n'+arr;
const crypto = require('crypto');
let s64 = crypto.createHmac("sha256", secret).update(sign).digest('base64');
let signature = encodeURIComponent(s64);
var bodyData = arr+"&Signature="+signature;
await fetch('https://mws.amazonservices.com/Products/2011-10-01', {
method: 'POST',
body: bodyData,
headers: {
'content-type': 'application/x-www-form-urlencoded',
'Accept': '',
},
})
.then(res => {
console.log(res)
})
.catch(error => {
console.log('Request failed', error);
});
}
amazon-mws package is also available for Node.
https://www.npmjs.com/package/amazon-mws
Related
Hello I'm trying to use the coinase api using axios to make request. I have set up the neccessary api authentication using SHA256 HMAC. I have been able to make some GET Request and got response. I have been trying to make a POST Request but i have been getting 401 status code.
const name = "Test BTC Address";
const body = {
name: name
}
var encHash = {
baseUrl: 'https://api.coinbase.com',
method: 'POST',
path: '/v2/accounts/bbc2e3f7-a851-50ab-b4b3-a0f2a700846f/addresses',
body: body,
scopes: "wallet:addresses:create"
};
const sign = generateHashKey(encHash, key.APISECRET);
console.log(sign);
const config = {
headers: {
'CB-ACCESS-SIGN': sign.signature,
'CB-ACCESS-TIMESTAMP': sign.timestamp,
'CB-ACCESS-KEY': key.APIKEY,
'CB-VERSION': '2021-10-15'
}
}
const url = `${encHash.baseUrl}${encHash.path}`
console.log(url);
var options = await axios.post(url, body, config);
return res.send({data: options.data})
} catch (error) {
// console.error(error);
return res.send({error})
} ```
I am currently writing to an API to try and get a token. I'm nearly there but fallen at the last hurdle..
const fs = require('fs');
const https = require('https');
const ConfigParams = JSON.parse(fs.readFileSync('Config.json', 'utf8'));
const jwt = require('jsonwebtoken');
const apikey = ConfigParams.client_id;
var privateKey = fs.readFileSync(**MY KEY**);
var tkn;
const jwtOptions = {
algorithm: 'RS512',
header: { kid: 'test-1' }
}
const jwtPayload = {
iss: apikey,
sub: apikey,
aud: **API TOKEN ENDPOINT**,
jti: '1',
exp: 300
}
jwt.sign(jwtPayload,
privateKey,
jwtOptions,
(err, token) => {
console.log(err);
//console.log(token);
tkn = token;
let = tokenPayload = {
grant_type: 'client_credentials',
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer/',
client_assertion: tkn
}
tokenAuthOptions = {
payload: tokenPayload,
host: **HOST**,
path: **PATH**,
method: 'POST',
}
https.request(
tokenAuthOptions,
resp => {
var body = '';
resp.on('data', function (chunk) {
body += chunk;
});
resp.on('end', function () {
console.log(body);
console.log(resp.statusCode);
});
}
).end();
}
)
the encoded token comes back fine for the first part, the https request though returns a problem.
the response I get back is grant_type is missing, so I know I have a formatting problem due to this x-www-form-urlencoded, but I can't figure out how to fix it.
here is what the website said:
You need to include the following data in the request body in
x-www-form-urlencoded format:
grant_type = client_credentials client_assertion_type =
urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion = <your signed JWT from step 4> Here's a complete
example, as a CURL command:
curl -X POST -H "content-type:application/x-www-form-urlencoded"
--data \ "grant_type=client_credentials\ &client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion="
END POINT
Ideally I want a solution using the https request, but if that's not possible I'm open to other solutions.
Any help is greatly appreciated.
Thanks,
Craig
Edit - I updated my code based on a suggestion to:
const params = new url.URLSearchParams({
grant_type: 'client_credentials',
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer/',
client_assertion: tkn
});
axios.post("URL", params.toString()).then(resp => {
console.log("response was : " + resp.status);
}).catch(err => {
console.log("there was an error: " + err);
})
But I'm still getting an error code 400, but now with less detail as to why. (error code 400 has multiple message failures)
Postman is the best.
Thank for #Anatoly for your support which helped to point me in the right direction. I had no luck so used postman for the first time, and found it had a code snippet section, with four different ways of achieving this using node.js.
The solution with Axion was:
const axios = require('axios').default;
const qs = require('qs');
var data = qs.stringify({
'grant_type': 'client_credentials',
'client_assertion_type': 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
'client_assertion': tkn
});
var config = {
method: 'post',
url: '',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.status));
})
.catch(function (error) {
console.log(error);
});
I believe the issue was that I was not passing the information into 'data:' in combination with the querystring problem. Using qs.stringify to format the object, then passing this into the data: key solved the problem.
I've written this code in my nodeJs backend
const url = "localhost:8080/job/test/build";
const username = "admin";
const password = "116c197495ef372f129b85a8a2ca4aadc2";
const token = Buffer.from(`${username}:${password}`, "utf8").toString(
"base64"
);
const data = {
}
axios
.post(url, {
headers: {
Authorization: `Basic ${token}`,
},
})
.then((response) => res.send(response)).catch((e) => {console.log(e)});
I'm getting the following error
The same request with same credential is working in postman.
use http in url, like this"
const url = "http://localhost:8080/job/test/build";
I am following the Authorization Code Flow (3-legged OAuth) documentation and I am now at step 3 where I need to use the authorization code in order to recieve an access token from LinkedIn. In the project I am using node.js, typescript and the node-fetch library. The following function creates a body with content type x-www--form-urlencoded since this is content type which LinkedIn require.
async function GetAccessToken(data: any) {
let body: string | Array<string> = new Array<string>();
for (let property in data) {
let encodedKey = encodeURIComponent(property);
let encodedValue = encodeURIComponent(data[property]);
body.push(encodedKey + "=" + encodedValue);
}
body = body.join("&");
const response = await fetch("https://www.linkedin.com/oauth/v2/accessToken", {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
body: body
}).then((res: any) => {
console.log("Result", res);
});
return response;
}
I do not recieve any errors and the response status is 200 but the response values I recieve are:
size: 0,
timeout: 0,
and what LinkedIn promise is:
access_token
expires_in
When I post the url with my parameters using postman the request goes through and I recieve the correct data which indicates the problem lies within my request function and not my values.
Any help is appreciated!
You need add all headers from postman
const urlencoded = new URLSearchParams();
urlencoded.append("client_id", env.LINKEDIN_CLIENT_ID);
urlencoded.append("client_secret",env.LINKEDIN_CLIENT_SECRET);
urlencoded.append("grant_type", "authorization_code");
urlencoded.append("code", code);
urlencoded.append(
"redirect_uri",
"http://localhost:3000/api/auth/linkedin-custom"
);
const accessTokenPromise = await fetch(
"https://www.linkedin.com/oauth/v2/accessToken",
{
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: urlencoded,
}
);
My angular app consumes a nodejs webapi :
var header = {
headers: new HttpHeaders()
.set('Authorization', `Bearer ${this.token}`)
}
var url="http://localhost:3000/user/deleteTodoFromUser/"+idUser+"/"+idTodo;
return this.http.put(url,"",header);
my api :
**router.put('/deleteTodoFromUser/:id/:idTodo', passport.authenticate('bearer'), (req, res) => {**
User.findByIdAndUpdate(req.params.id,{ $pull:{todos:{$in:[req.params.idTodo]}}},{new:true},(err, usr) => {
if (err) {
res.send(err);
}
if(usr)
{
res.send(usr);
}
else
{
res.status(400).send("bad request");
}
**My api works properly in postman **
** CORS are enabled **
in angular doesn't, it returns 400 (bad request )
let params = new HttpParams();
params = params.append('id', idUser);
params = params.append('idTodo', idTodo);
this.http.put(url, "", { headers: headers, params: params });
when I add params parameter in the request , It becomes like that
http://localhost:3000/user/deleteTodoFromUser/?id=5dfa958e98710030207952cc&idTodo=5dfa976ea4ea1d31f8919ee5
but the api waits the request like that :
http://localhost:3000/user/deleteTodoFromUser/5dfa958e98710030207952cc/5dfa976ea4ea1d31f8919ee5
the difference is my api waits the request id without id?= and idTodo?=
and I want it like that
400 Bad Request, Whatever the endpoint is expecting, it's not getting it.
Seems that there is an issue while passing params to your API or the token value sent to your API is invalid.
This is another way to send parameters to your API instead of Appending them to the URL
const headers = new HttpHeaders()
.set('Authorization', `Bearer ${this.token}`);
let params = new HttpParams();
params = params.append('id', idUser);
params = params.append('idTodo', idTodo);
this.http.put(url, "", { headers: headers, params: params });
If it's not the case try to make a call using real parameters value and a valid token that works in Postman in order to detect the root cause of the error that you are getting.