Missing Authorization header when send http request from browser - javascript

I have an application in nodejs with jwt authorization, when I send a get from posman the authentication header is found but when I send it from the browser, the authorization header is missing.
Here is the node code, I'm trying to get the authorization header in the verifyToken method, but is not there:
'use strict';
var SwaggerExpress = require('swagger-express-mw');
var app = require('express')();
module.exports = app; // for testing
var _ = require('lodash');
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var config = {
appRoot: __dirname // required config
};
app.set('superSecret', config.secret); // secret variable
// bootstrap database connection and save it in express context
app.set("models", require("./api/model"));
var a = app.get("models").Role;
var repositoryFactory = require("./api/repository/RepositoryFactory").init(app);
var verifyToken = function (req, res, next) {
// verify token and read user from DB
// var token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiTm9tYnJlVXN1YXJpbyI6ImQiLCJQYXNzd29yZCI6IiQyYSQxMCRYS3BJM2ZDRVFoSzVKUFBQWEdIVVZPbUVPQTZsRVRoZDRtWHl4a0tDeGtUcEhvY0U0UTNILiIsImNyZWF0ZWRBdCI6IjIwMTYtMDktMDVUMTg6Mjk6MTYuMDAwWiIsInVwZGF0ZWRBdCI6IjIwMTYtMDktMDVUMTg6Mjk6MTYuMDAwWiIsInByb2Zlc2lvbmFsSWQiOm51bGwsInByb2Zlc2lvbmFsIjpudWxsLCJpYXQiOjE0NzMyNTczMjcsImV4cCI6MTQ3MzI5MzMyN30.CKB-GiuvwJsDAVnKsWb1FktI9tJY57lSgPRVEfW3pts';
var token = req.headers.authorization;
jwt.verify(token, 'shhhhh', function (err, decoded) {
if (err) {
res.status(403).json({ success: false, message: 'Failed to authenticate token.' });
} else {
// if everything is good, save to request for use in other routes
req.user = decoded;
next();
}
});
};
SwaggerExpress.create(config, function (err, swaggerExpress) {
if (err) { throw err; }
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-CSRF-Token, X-Requested-With, Origin, client-security-token, X-Requested-With, Content-Type, Accept, Authorization");
res.setHeader('Content-Type', 'application/json');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.use(verifyToken);
// install middleware
swaggerExpress.register(app);
var port = process.env.PORT || 10010;
app.listen(port);
});
I don't know what configuration I'm missing.

The issue was that I was trying to get the authorization token from the OPTIONS method, this method is sent before the actual get, port, put etc, when is a CORS request. So I was trying to get the authorization header from it and it was not there and the method failed.
The solution was to set in the verify token method a validation like this:
if (req.method !== OPTIONS){
}

I think it is easier if you can change the code in verifyToken function : var token = req.headers.authorization; become var token = req.headers.authorization || req.query.access_token || req.body.access_token;
So in the browser, you can add token in "access_token" query param to authenticate in server instead of setting the header.
Hope it is helpful for you !

You need to set those headers in your browser, try use this chrome plugin called ModHeader https://chrome.google.com/webstore/detail/modheader/idgpnmonknjnojddfkpgkljpfnnfcklj

Try adding the following code in .htaccess. Apache removes the Authorization Header. This will ensure it is not removed.
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

Related

How to Form Authentication Header for Axios Request to Node.js App Using Passport Local Authentication?

I have a node.js app and am developing a separate single page app (that will eventually be converted into Android and iOS native apps). I'm setting up an API on the node.js app and am struggling with authentication. The node.js app is using passport-local-mongoose for authentication and I store user data in a MongoDB backend. For testing/dev, the single page app is running on http://localhost:1234/.
My endpoint looks like:
exports.getDevicesAPI = async (req, res) => {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET, POST');
res.header('Access-Control-Allow-Headers: Authorization');
const devices = await Device.find({ owner: req.user._id });
res.json(devices);
};
I can GET this no problem with something like:
const axios = require('axios');
const url = 'http://localhost:7777/api/devices';
function getDevices() {
axios
.get(url)
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.log(error);
});
}
I want to add authenticate = passport.authenticate('header', {session: false, failWithError: true}); on the server side to provide authentication, but the following gives me Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:7777/api/devices. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing):
const axios = require('axios');
const url = 'http://localhost:7777/api/devices';
const username = myUsername;
const password = myPassword;
const axiosConfig = {
headers: {
'Content-Type': 'application/json',
},
Authorization: {
username,
password,
},
};
function authenticate() {
axios
.post(url, axiosConfig)
.then(function(response) {
console.log('Authenticated');
})
.catch(function(error) {
console.log('Error on Authentication');
});
}
Routes (for testing):
router.get('/api/devices', catchErrors(deviceController.getDevicesAPI));
router.post('/api/devices', catchErrors(deviceController.getDevicesAPI));
What am I missing?
You are having issues with CORS(Cross-Origin Resource Sharing) Restrictions. Read more about CORS here.
I believe this part of your code is meant to handle the CORS:
exports.getDevicesAPI = async (req, res) => {
// ...
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET, POST');
res.header('Access-Control-Allow-Headers: Authorization');
// ...
};
However, the mistake here is that the setting of these CORS headers is tied to a route, i.e the getDevicesAPI route which is not supposed to be. For requests that are likely to modify resources in another origin(e.g the POST to getDevicesAPI route), the browser would first send a preflight request with the OPTIONS Http method before sending the actual request, the response to the preflight request is where the necessary CORS response-headers is expected to be set. You can find explanations on preflight requests here.
I would typically add a middleware like this above the other routes:
router.all('*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', '*');
next();
});

javascript / NodeJS - Sending Data from nodejs app to html file using send and get

id like to build a sftp client app using nodejs. Currently i am able to receive lsEntries from the Server and print them to the Terminal.
var Client = require('ssh2').Client;
var express = require('express');
var app = express();
var cors = require('cors');
app.use(cors);
var connSettings = {
host: myserver,
port: 22,
username: myuser,
password: passwd
};
var remotePathToList = '/';
var conn = new Client();
conn.on('ready', function(){
conn.sftp(function(err, sftp){
if(err) throw err;
sftp.readdir(remotePathToList, function(err, list){
if(err) throw err;
var contents = []
contents = (list);
for(var i = 0; i < contents.length; i++){
console.log(contents[i].filename);
}
app.get('/data', function(req, res){
res.send(contents);
});
app.listen(3000);
//close connection
conn.end();
});
});
}).connect(connSettings);
In order to receive the data in my frontend i have the folowing JQuery Code:
$(document).ready(function(){
$("button").click(function(){
$.get('http://localhost:3000/data', {}, function(data){
var myData = (data);
console.log(myData.length);
});
});
});
But i don't receive an answer. Sometimes i get ERR_EMPTY_RESPONSE after a very long time of waiting. Note that i'm using 'cors' to prevent the Access-Control-Allow-Origin Error. However, when i type localhost:3000 in my browser i get the data printed to the screen (JSON).
What is the correct way to access the lsEntry array from the frontend?
Thanks in advance
Ah, i solved the problem. Using cors didn't work, but i found a solution, that allows cors with express:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With,
Content-Type, Accept");
next();
});
It replaces
var cors = require('cors');
app.use(cors);
and works. I don't know why the npm package didn't work, but i found the solution here.

how to setup cors for get requests in express?

I have been reading and trying these two configurations for npm cors
https://www.npmjs.com/package/cors
var express = require('express')
var cors = require('cors')
var app = express()
var whitelist = ['http://example1.com', 'http://example2.com']
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
this at first, this seem to work well but then I just figured...
this only works with post methods not get methods..
get will return the error....
What I want to do is...I have a different backend apis which have get and post method.
I use another another to call the get and post method from this api.
for example, frontend uses example.this-one.com and try to send get / post request to example.that-two.com as mentioned post works but not get
There are a few other methods which I tried from the documentation but either get works but it'll be open to public that anyone knows the url will be able to see the data for get, but I want to set restriction that only example.this-one.com can get example.that-two.com
Can someone give me some advice on this?
Thanks in advance.
The following code is working for me:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With,Content-Type, Accept");
next();
});
Since the server is http://example.that-two.com, put the client (http://example.this-one.com) on the whitelist
var whitelist = ['http://example.this-one.com']
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
},
methods: ['GET']
}
This will allow all GET requests from http://example.this-one.com
Then call the middleware:
app.use(cors(corsOptions));

Making CORS Request in Node.js/Express and AngularJS

I have seen many answers in stack overflow which says setting response headers will make you "CORS" request.But no solution worked for me.I have written the following code:
//Server.js Code
var express = require('express'),
app = express();
app.all('*',function(req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
next();
I am trying to access the content from the URL using $http in client side:
//Controller.js
$http.get('http://domainA.com/a/ipadapi.php?id=135&client=ipad').success(function(response){
alert("I got response");
});
It's showing the following error in console.
XMLHttpRequest cannot load http://domainA.com/a/ipadapi.php?id=135&client=ipad The 'Access-Control-Allow-Origin' header has a value 'http://example.xxxxx.com' that is not equal to the supplied origin. Origin 'http://localhost:3000' is therefore not allowed access.
Note:I am new to nodeJS,Express and AngularJs
When you are passing credentials with CORS, you need to lock down the accepted origins. Try changing your origins from * to "localhost:3000"
See cross origin resource sharing with credentials
Change the header info from
res.setHeader("Access-Control-Allow-Origin", "*");
TO
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
If you're not the owner of domainA then you cannot send CORS headers from that domain. You can use your Node server as middleware, and proxy the request from your server to domainA. Your server can send CORS headers back to your angular app. pseudo code with hapi and needle:
import Hapi from 'hapi'
import needle from 'needle'
const server = new Hapi.Server()
server.connection({
port: 9090
, routes: {
cors: true
}
})
const handler = (req, reply) => {
const url = 'https://domainA.com'
, data = {
body: 'code'
}
needle.post(url, 'body=${data.body}', function(err, res) {
let json = JSON.parse(res.body)
reply(json.data)
})
}
server.route({
method: 'GET',
path: '/route/{id}',
handler: handler
}
)
server.start( err => {
if( err ) {
console.error( 'Error was handled!' )
console.error( err )
}
console.log( 'Server started at ${ server.info.uri }' )
})

Post request from Backbone client to NodeJS service

Somehow I am not able to send data from Backbone model to NodeJS service.
Backbone Model
var Money = Backbone.Model.extend({
url: 'http://localhost:3000/sendCoins',
defaults: {
fromAddress: "",
toAddress: "",
amount: ""
},
transferMoney: function(req, resp) {
//get field values
console.log(req.fromAddress); //prints fine
this.save();
}
});
var transferMoney = new Money();
Node JS service
var app = express();
app.listen(3000);
app.use(express.json());
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', '*');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
app.post('/sendCoins', function(req, res) {
console.log(req.body.toAddress);
console.log(JSON.stringify(req.body));
console.log(req.body.amount);
});
When I post the request from backbone view console.log(JSON.stringify(req.body)); prints {"fromAddress":"","toAddress":"","amount":""}.
As mentionned by M Omary, you need to use the body parser in order to have access to req.body. Add the following code above app.post to see if it works:
app.use(express.bodyParser());

Categories