CSRF token validation failed in nodejs while posting data to odata service - node.js

var request = require('request');
var username = '';
var password = '';
var url = 'http://207.188.73.88:8000/sap/opu/odata/sap/ZTEE_TIME_SRV/ZTEERESERVESet(Time=time\'PT11H00M00S\',Date=datetime\'2014-03-11T00%3A00%3A00\',Location=\'TAJ\',Number=3)';
var auth = 'Basic ' + new Buffer(username + ':' + password).toString('base64');
// i am trying to post data to odata service but the problem is that i could not get valid token from get service to use it in the post method i am first send get method
request(
{
url: url,
headers: {
'Authorization': auth,
'x-csrf-token': 'Fetch',
},
},
function(error, response, body) {
console.log('JSON data ' + response);
console.log('body' + body);
// trying to get the token to use in post
console.log(response.headers);
request(
{
url: url,
headers: {
here it says invalid token
'Authorization': auth,
'X-CSRF-TOKEN': 'u6piLO58XoK6udOkQ5Naww==',
},
method: 'POST',
//Lets post the following key/values as form
form: {
Time: 'PT11H00M00S',
Date: '2014-03-11T00%3A00%3A00',
Location: 'TAJ',
Number: 3,
},
},
function(error, response, body) {
console.log(body);
},
);
},
);

I got the solution.
I was trying to do this with POSTMAN, and it was working fine.
The thing is that when i was asking for CSRF token it always gave me the same back.
But when i tried with node, every time was different. Then i realized that the cookie was missing.
And thats all, the solution is to send the cookie at least in POST requests.
The set-cookie of the "Fetch" request must be sent in the Post request as Cookie beside the x-csrf-token
I put the example in typescript, but in js doesnt change so much, the idea is the same.
The example is not the best case but is complete to figure out how it works
let headers = {
"Authorization": "Basic " + new Buffer(username + ":" + password).toString("base64"),
"Content-Type":"application/json",
"Accept":"application/json",
"x-csrf-token":"Fetch" // get CSRF Token for post or update
};
// if you are using session vars
if (req.session.headers && req.session.headers.cookie) {
headers['Cookie'] = req.session.headers.cookie;
} else {
req.session.headers = {}; // initialize as object
}
let opts = {
url: "https://{host}:{port}/sap/opu/odata/sap/MD_SUPPLIER_MASTER_SRV",
qs: params1, // params set before, not set in the example
headers: headers,
json: true,
}
request(opts, (error: any, response: any, body: any): any => {
if (!error && response.statusCode === 200) {
if (response.headers["set-cookie"]) {
req.session.headers.cookie = response.headers["set-cookie"]; // store Cookie in session
headers['Cookie'] = req.session.headers.cookie; // set in headers for the next call. I guess this is the part you missed
}
if (response.headers['x-csrf-token']) {
req.session.headers.csrf = response.headers['x-csrf-token']; // store csrf-token in session
headers['x-csrf-token'] = req.session.headers.csrf; // set in headers for the next call
}
let options: request.Options = {
url: "https://{host}:{port}/sap/opu/odata/sap/MD_SUPPLIER_MASTER_SRV/C_BusinessPartnerSupplierEdit",
method: 'POST',
headers: headers,
qs: params2, // params set before
json: true,
}
request(options, (error: any, response: any, body: any): any => {
res.json(body);
});
}
});
Regards

Related

How to Set Params with Node Get Request

I am trying to make a get request using the NPM Request module and am having trouble passing in a params argument.
Going through the docs I can't tell what the correct syntax is.
makeRequest(req, res, num, cookie) {
request({
headers: {
'Cookie': cookie
},
url: 'https://api.domain.com/path',
params: num // this is incorrect
},
(error, response, body) => {
res.json({
msg: "Success"
})
}
})
}
How can I pass a params argument into a request?
https://www.npmjs.com/package/request
qs - object containing querystring values to be appended to the uri
request({
headers: {
'Cookie': cookie
},
url: 'https://api.domain.com/path',
qs: { num: 1}
})
This should create a url
https://api.domain.com/path?num=1

Node JS Request Printing nothing in console

I'm making an post call using the nodejs requests module. However, the console.log statements seems to be not working for either the error or the response.body that I am trying to get.
My POST request needs the following headers -
Accept : "application/json"
Content-Type : "application/json"
Authorization : Basic + Base64Encoded(username+password)
The post body is something like this
Body:
{
"arg_1" : "a_string_key"
, "arg_2" : "a_string"
, "arg_3" : "a_string"
, "arg_4" : "some_value"
, "arg_5" : "some_string"
, "arg_6" : "<yyyy-mm-dd>"
, "arg_7" : "<yyyy-mm-dd>"
}
My code does nothing but send a POST request and checks if the response.statusCode ==200
Here is what I am doing
var int_user = "username";
var int_pass = "password";
var encoding = "base64"
var auth = "Basic" + new Buffer(int_user + int_pass).toString(encoding);
var headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": auth
}
var options = {
url: 'URL_I_WANT',
// method: 'POST',
headers: headers,
body : {
"arg_1": "a_string_key",
"arg_2": "a_string",
"arg_3": "a_string",
"arg_4": "some_value",
"arg_5": "some_string",
"arg_6": "<yyyy-mm-dd>",
"arg_7": "<yyyy-mm-dd>"
},
json: true
}
console.log('Before request');
request.post(options, function(error, response) {
if (error) {
console.log(error);
}
try {
if (!error && response.statusCode == 200) {
console.log(response.body);
console.log('Success');
}
} catch (error) {
console.log(error)
}
});
console.log('After request');
The code runs without any glitch and I get the before and after request console statements. However the statements inside the requests do not appear in the console, which means my request is not going through. I am not able to understand this. Shouldn't an error come if there is an issue with the request itself? Any if the request is failing, why isn't the error printed out?
This could be because your node process is auto-closed and it will exit before the async request to finishes (haven't looked into it but it might be something configurable). I've seen such set-up on repl.it for example.
To overcome this(if not configurable), you could wrap your code in an async function and use the request-promise to call await request.
var request = require('request-promise-native');
var int_user = "username";
var int_pass = "password";
var encoding = "base64"
var auth = "Basic" + new Buffer(int_user + int_pass).toString(encoding);
var headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": auth
}
var options = {
url: 'https://google.com',
method: 'POST',
headers: headers,
body : {
"arg_1": "a_string_key",
"arg_2": "a_string",
"arg_3": "a_string",
"arg_4": "some_value",
"arg_5": "some_string",
"arg_6": "<yyyy-mm-dd>",
"arg_7": "<yyyy-mm-dd>"
},
json: true
};
console.log('Before request');
async function main() {
try {
const response = await request.post(options);
if (response.statusCode === 200) {
console.log(response.body);
console.log('Success');
process.exit();
}
console.log(`Bad statusCode:${response.statusCode}`);
}
catch (error) {
console.log(error);
}
}
main();
you can check-out the code below
a link to the code above, working on repl.it

csrf token validation fail in post request while calling sap odata service

var Array = require('node-array');
var request = require("request");
username = "user24",
password = "",
auth = "Basic " + new Buffer(username + ":" + password).toString("base64");
var options = { method: 'GET',
url: "http://207.188.73.88:8000/sap/opu/odata/sap/ZTEE_SUGGEST_SRV/ZteeSuggestSet?$filter=Number eq 5 and Date eq datetime'2014-03-11T00%3A00%3A00'&$format=json",
headers:
{
i am fetching xcsrf token here
'x-csrf-token': 'fetch',
'content-type': 'application/json',
authorization: auth } };
request(options, function (error, response, body) {
if (error) throw new Error(error);
// console.log(response.headers['x-csrf-token']);
var token="'";
token+=response.headers['x-csrf-token'];
token+="'";
//console.log(token);
var options = { method: 'POST',
url: 'http://207.188.73.88:8000/sap/opu/odata/sap/ZTEE_TIME_SRV/ZTEERESERVESet',
and setting the csrf token here but it give me error that scrf token required or invalid
headers:
{
authorization: auth,
'x-csrf-token': token,
'content-type': 'application/json' },
body:
{ Time: 'time\'PT11H00M00S\'',
Date: 'datetime\'2014-03-11T00%3A00%3A00\'',
Location: 'AAJ',
Number: 3 },
json: true };
request(options, function (error, response, body) {
if (error) throw new Error(error);
// console.log(body);
here it shows that token rrequired but i am already setting that in header
console.log(response.headers['x-csrf-token']);
});
});
I had faced similar situation while working with SAP WEBIDE.
I had disabled the request for token and i was able to establish the connection with Odata services. I did something like this code snippet in my component.js file.
var oModel = new sap.ui.model.odata.ODataModel(this.getMetadata().getConfig().serviceUrl);
oModel.disableHeadRequestForToken = true;
serviceURL contained the URL to Odata Service.
You can try to disable the CSRF token request and check.

Async request module in Node.js

I am creating a project using Node.js. I want to call my requests in parallel. For achieving this, I have installed the async module. Here is my code:
var requests = [{
url:url,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + req.cookies.apitoken
},
json: finalArr,
}];
async.map(requests, function(obj, callback) {
// Iterator function
request(obj, function(error, response, body) {
if (!error && response.statusCode == 200) {
// Transform data here or pass it on
var body = JSON.parse(body);
callback(null, body);
}
else {
var body = JSON.stringify(body);
console.log(body)
callback(error || response.statusCode);
}
});
})
I got undefined every time in console.log(body). When I am using GET requests using this module for other requests then everything works fine.
It looks like you're using the request module, but didn't tag it as such.
If I'm right, then your options object is incorrect, from the documentation there's not a data key that's respected. Instead, you should use body or formData or json depending on what kind of data you're pushing up. From your headers, I'd go with json.
var requests = [{
url:url,
method: 'POST',
headers: { // Content-Type header automatically set if json is true
'Authorization': 'Bearer ' + req.cookies.apitoken
},
json: finalArr,
}];

oAuth code exchange for secret token

I'm making an app that is supposed to use oAuth to authenticate players from the Blizzard servers, I want to access their character info.. and I can't figure out how to ask for the secret_token. I guess I'm doing my post request wrong below is the code I'm using
app.post('/', function(req, res) {
var code = req.body.code; //this is the code i get ounce the player is redirected back to my redirect_uri
var redirectUri = "https://localhost:3000/oauth_callback.html";
var scope = "wow.profile";
var key = "they client_id i was given";
var secret = "they secret I was given";
var grantType = "authorization_code";
var tokenUri = "https://us.battle.net/oauth/token";
var uriBody = "?client_id=" + key + "&client_secret=" + secret + "&grant_type=authorization_code&code=" + code + "&redirect_uri=" + redirectUri + "&scope=" + scope;
request({
url: tokenUri, //URL to hit
method: 'POST',
headers: {
'Content-Type': "application/x-www-form-urlencoded",
},
body: uriBody //Set the body as a string
}, function(error, response, body){
if(error) {
console.log(error);
} else {
console.log(response.statusCode, body);
}
});
so basically I'm getting the code making a post request to my server with it, and then triggering a post request to the blizzard server trying to exchange my code for an access token.
The error I get is:
401 '{"error":"unauthorized","error_description":"An Authentication object was not found in the SecurityContext"}'
I'm using Node.js & request.js to make the post, my guess is I'm not making a proper request post request?
I think body key is not acceptable in request.
Send data in json if content-type is JSON or form if content-type is x-www-form-urlencoded
Like this
request({
url: tokenUri, //URL to hit
method: 'POST',
headers: {
'Content-Type': "application/x-www-form-urlencoded",
},
form: uriBody //Set the body as a string
}, function(error, response, body){
if(error) {
console.log(error);
} else {
console.log(response.statusCode, body);
}
});
finally! here is how I got it to work!
qs = query-string.js library...
var token_params = qs.stringify({
client_id: key,
client_secret: secret,
code: code,
scope: scope,
grant_type: 'authorization_code',
redirect_uri: redirectUri
});
request('https://us.battle.net/oauth/token?' + token_params, function(error, response, body){
if (error) {
console.log(error);
} else {
console.log(body)
}
});

Resources