Node.js https.request method using client credentials - node.js

I am trying to make a request for an access token using https.request but I keep getting the following error:
"error":"invalid_request","error_description":"Missing grant type"
In the Node.js HTTPS.Request documentation there isn't any reference for how to set the grant type. I believe I need to set it in the body of the request, but there is also no reference to attaching a body to the request. I am attempting to do it with the payload variable but obviously that isn't working. I am also trying to do this request with 0 or as little dependencies as possible.
function getAccessToken() {
const https = require('https')
const payload = {
"grant_type": "client_credentials"
}
const options = {
"hostname": url,
"method": "POST",
"path" : "/oauth2/token",
"port" : 443,
"encoding": "utf8",
"followRedirect": true,
"headers": {
"Authorization": "Basic <base64 encoded client_id:client_secret>",
"scope": "PARTNER_READ"
},
"payload": payload,
'muteHttpExceptions': true
}
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`)
res.on('data', d => {
process.stdout.write(d)
})
})
req.on('error', error => {
console.error(error)
})
req.end()
}
Any help would be appreciated!

Just to close the loop on this, I was missing the 'Content-Type' in the header which I think was causing the "Missing Grant Type" error because it couldn't parse the body. I also needed to write the postData to the request right before the req.end(). So thank you #Klaycon for that point in the right direction!
Here is my updated code:
function getAccessToken() {
const querystring = require('querystring');
const https = require('https')
const postData = querystring.stringify({
'grant_type': 'client_credentials'
});
const options = {
"hostname": url,
"method": "POST",
"path" : "/oauth2/token",
"port" : 443,
"encoding": "utf8",
"followRedirect": true,
"headers": {
"Authorization": "Basic <base64 encoded client_id:client_secret>",
"Content-Type": 'application/x-www-form-urlencoded',
"Content-Length": Buffer.byteLength(postData),
},
'muteHttpExceptions': true
}
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`)
res.on('data', d => {
process.stdout.write(d)
})
})
req.on('error', error => {
console.error(error)
})
req.write(postData);
req.end()
}

Related

how to use access token to call another post request?

I have this post request to get access token and its working fine but would like to know how can I use this access token to call another post request ? Or how do I use async or promises to use in this ?
Here is my code :
function getAccessToken() {
const querystring = require('querystring');
const https = require('https')
const postData = querystring.stringify({
'grant_type': 'client_credentials'
});
const options = {
"hostname":'api.xxx.com',
"method": "POST",
"path" : "/token",
"port" : 443,
"encoding": "utf8",
"followRedirect": true,
"headers": {
"Authorization": 'Basic ' + Buffer.from("client_id" + ':' + "client_secret").toString('base64'),
"Content-Type": 'application/x-www-form-urlencoded',
"Content-Length": Buffer.byteLength(postData),
},
'muteHttpExceptions': true
}
const body = []
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`)
res.on('data', (chunk) => body.push(chunk))
res.on('end', () => {
const access_token = Buffer.concat(body).toString()
console.log(access_token)
})
})
req.on('error', error => {
console.error(error)
})
req.write(postData);
req.end()
}
getAccessToken();
You can save token in database,file or other memory database and use it in all requests in the Authorization header but depends on type of token,for example for set JWT token:
request.setHeader('Authorization', 'Bearer '+accessToken)
OR in option object:
options = {
host: '<URL>',
path: '<path of endpoint>',
port: '<portNumber>',
headers: {'Authorization', 'Bearer '+accessToken}
};
also for the async request to another endpoint, you can use Axios axios example:
const axios = require('axios').default;
const sendGetRequest = async () => {
try {
const resp = await
axios.get('https://jsonplaceholder.typicode.com/posts', {
headers: {
'authorization': 'Bearer YOUR_JWT_TOKEN_HERE'
}
});
console.log(resp.data);
} catch (err) {
// Handle Error Here
console.error(err);
}
};
sendGetRequest();

Axios POST to URL without urlencoding reserved character

I'm using Axios to POST to an external service where the URL requires including multiple apostrophes. The receiving service does not decode the URL of the received request, forcing us to figure out a way to POST to an unencoded URL.
I've not been able to discern any accessible way in which we could accomplish this.
const response = await axios.post("https://foo.bar/Company('ACME')", body, {
headers: {
Authorization: this.authHeader,
'Content-Type': 'application/json'
}
})
The crux of the issue is having the URL include Company('ACME') without the apostrophes being URL-encoded to %27.
I've figured this to be possible with the native HTTPS module, but I'd like to see if this couldn't be accomplished with Axios (or a similar library).
const https = require('https');
const data = JSON.stringify({
company: 'Acme Corporation'
});
const options = {
"hostname": "foo.bar",
"path": "/Company('ACME')",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"Content-Length": data.length
}
};
const req = https.request(options, (res) => {
let data = '';
console.log('Status Code:', res.statusCode);
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Body: ', JSON.parse(data));
});
}).on("error", (err) => {
console.log("Error: ", err.message);
});
req.write(data);
req.end();
Is there any way to accomplish this with Axios or a similiar library?

Cannot send firebase push notification from lambda

I am hoping someone can help me point my mistake here.
I am trying to send a firebase push notification through a lambda using the HTTP legacy endpoint
https://fcm.googleapis.com/fcm/send
I am following the guide from:
https://craigrussell.io/2019/03/send-firebase-fcm-push-notification-from-aws-lambda/
Here is my code:
const authHeader ='key=A****IV';
const deviceToken ='eut4****pm';
console.log('sending Push notification');
return new Promise((resolve, reject) => {
const options = {
host: 'fcm.googleapis.com',
path: '/fcm/send',
method: 'POST',
headers: {
'Authorization': authHeader,
'Content-Type': 'application/json',
},
};
const req = http.request(options, (res) => {
console.log('success');
resolve('success');
});
req.on('error', (e) => {
console.log('failuree' + e.message);
reject(e.message);
});
// const reqBody = '{"to":"' + deviceToken + '", "priority" : "high"}';
const reqBody = '{"to":"' + deviceToken + '", "priority": "high", "notification": {"title": "Test", "body": "Test"}}';
console.log(reqBody);
req.write(reqBody);
req.end();
});
};
I do not receive any push notification after this . Am i doing something wrong here?
I think the key point is that you use the http module. Actually, it works well when using https module on my side.
var https = require('https');
The complete code is as follows:
var https = require('https');
exports.handler = async(event) => {
const authHeader = 'key=AA***y';
const deviceToken = 'fG***-';
return new Promise((resolve, reject) => {
const options = {
host: 'fcm.googleapis.com',
path: '/fcm/send',
method: 'POST',
headers: {
'Authorization': authHeader,
'Content-Type': 'application/json',
},
};
console.log(options);
const req = https.request(options, (res) => {
console.log('success');
console.log(res.statusCode);
resolve('success');
});
req.on('error', (e) => {
console.log('failuree' + e.message);
reject(e.message);
});
// const reqBody = '{"to":"' + deviceToken + '", "priority" : "high"}';
const reqBody = '{"to":"' + deviceToken + '", "priority": "high", "notification": {"title": "Test", "body": "Test"}}';
console.log(reqBody);
req.write(reqBody);
req.end();
});
};
For more details, you can see the res field after http request, it will show statusCode 403 when you use http.

Node.js post request not executing callback

So ive got this function:
async function getRandomNumber(){
const https = require('https');
const url = 'https://api.random.org/json-rpc/2/invoke';
const params:object = {
"jsonrpc": "2.0",
"method": "generateIntegers",
"params": {
"apiKey": process.env.randomApiKey,
"n": 1,
"min": 1,
"max": 10,
},
"id": 42
}
const options = {
hostname: 'https://api.random.org',
port: 443,
path: '/json-rpc/2/invoke',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(JSON.stringify(params))
}
};
const req = https.request(options, (res:any) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk:any) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
});
});
req.on('error', (e:any) => {
console.error(`problem with request: ${e.message}`);
});
// Write data to request body
req.write(JSON.stringify(params));
req.end();
}
which is being called like this:
await getRandomNumber();
But the call back does not log anything, so it seem that the post request is not beeing executed? How can I make this work?
Is it better to use the request module?
The problem is that you are trying to await a callback style function which doesn't return a promise. You need to return a promise to await it.
Regarding request module, i wouldn't suggest using it as it is not maintained. You can read more here
https://github.com/request/request/issues/3142
This also talks about alternative libraries
https://github.com/request/request/issues/3143
One of the library is got which can simplify the work which are doing. the code will look like
const getResponse = await got("http://someurlhere");
console.log(getResponse.body);

Using CSRF Token from GET and Uses that in POST | 403 Forbidden | AWS Lambda

I am creating node.js function through aws lambda which makes a GET request to Hybris Market Place and gets a CSRF Token. Then I am using that token to make another POST request to post some data to Hybris Market place but I am getting an error of 403 Forbidden. Same thing works in Postman which I believe due to POSTMAN keeps GET session alive and hence CSRF token is still valid. How May I achieve that in AWS Lambda function. Below is my code. I am using promise to make two requests.
const https = require('https');
exports.handler = async (event, context, callback) => {
const tokenOptions = {
"host": "*******.s4hana.ondemand.com",
"path": "/sap/opu/odata/sap/***********/",
"port": null,
"headers":{
"authorization": "Basic ************=",
"cache-control": "no-cache",
"x-csrf-token": "fetch"
},
"method": "GET"
};
var getToken = (tokenOptions) => {
return new Promise((resolve,reject)=>{
const req = https.request(tokenOptions, (res) => {
var xToken = res.headers["x-csrf-token"];
var sCookies = res.headers["set-cookie"];
var response = [xToken,sCookies]
res.on('data', () => {
console.log('Successfully processed HTTPS response');
resolve(response);
});
res.on('end', () => {
});
});
req.on('error', function(){
reject('Request to get token failed.');
});
req.end();
});
};
var postContent = (response) => {
return new Promise((resolve,reject)=>{
var options = {
"method": "POST",
"host": "*********-***.s4hana.ondemand.com",
"path": "/sap/opu/odata/sap/*********/*******",
"port":null,
"headers":
{ "authorization": "Basic *******==",
"x-csrf-token": response[0],
"accept": "application/json",
"content-type": "application/json",
"cache-control": "no-cache",
},
"cookie":response[1],
"body":
{
/* Data I want to POST */
},
"json": true
};
const req = https.request(options, (res,data) => {
console.log(res.statusCode);
res.on('data', () => {
resolve('Successfully submitted.');
});
res.on('end', () => {
});
});
req.on('error', function(err,res){
reject('Request to get Post failed.');
});
req.end();
});
};
getToken(tokenOptions).then((response) =>{
console.log('Result: ' +response[0]);
return postContent(response);
}).then((successMsg) =>{
callback(null,successMsg);
}).catch((errMsg)=>{
callback();
});
};

Resources