I am testing my app with mocha and I would like to test a HTTP response header code depending on the credentials that I sent to it with a basic HTTP authentication.
In the client side, I made the AJAX call to the server like this:
$.ajax({
type: 'GET',
url: url,
beforeSend: function(xhr){
xhr.setRequestHeader("Authorization", "Basic " +btoa("username:password") );
},
success:function(rsp){
// do whatever I need;
}
});
And it works perfectly. It the credentials are wrong, then the website will respond wit a 302
In my test file (mocha), I try to sent the same request but for some reason it does not work.
Here is the different way I tried:
it('should return 302 because wrong credentials', function(done){
var auth = "Basic " +new Buffer("username:password").toString('base64');
var options = {
url: url,
headers: {
"Authorization": auth
}
};
request.get(options, function(err, res, body){
console.log(res.statusCode);
assert.equal(302, res.statusCode);
done();
});
});
-----------------------
it('should return 302 because wrong credentials', function(done){
request.get(url,
{
'auth': {
'username':'username',
'password':'password'
}
},
function(err, res, body) {
assert.equal(302, res.statusCode);
done();
});
});
But, in anyway, I get a HTTP 200 response code.
So why? And how should I handle it?
Ps: For those who are very cautious, the client is not to be used publicly and thus I allow myself to put credentials in it.
EDIT: To be more precise, you will find below the server code (NodeJS) which handle the request
function checkAuth(req, result, next){
var header = req.headers['authorization'];
// Ignore the preflight OPTION call
if(header != undefined){
var tmp = header.split(/\s+/).pop();
var credentials = new Buffer(tmp, 'base64').toString();
var parts = credentials.split(/:/);
var username = parts[0];
var password = parts[1];
bcrypt.compare(username, config.get.username, function(err, res){
if(res){
bcrypt.compare(password, config.get.password, function(err, res){
if(res){
next();
} else {
return result.redirect('/');
}
});
} else {
return result.redirect('/');
}
});
} else {
return result.redirect('/');
}
}
app.get('/server', checkAuth, getData.getMessages);
And the method getData.getMessage() return the following:
return result.status(200).json(res);
request automatically follows redirects so you'll need to disable followRedirect to read 3xx responses.
var options = {
url: url,
followRedirect: false,
headers: {
"Authorization": auth
}
};
For HTTP Basic authentication you can also use http-auth module.
// Authentication module.
var auth = require('http-auth');
var basic = auth.basic({
realm: "Simon Area.",
file: __dirname + "/../data/users.htpasswd" // gevorg:gpass, Sarah:testpass ...
});
// Creating new HTTP server.
http.createServer(basic, function(req, res) {
res.end("Welcome to private area - " + req.user + "!");
}).listen(1337);
Related
I saw many tutorials on jwt authentication but every video maker uses Postman to show what's happening and they pass on the header in the headers section while requesting a URL in Postman. I tried to do it with JavaScript but I was not able to do it.
I want to do jwt authentication but after token generation, I send it to client side to use it for further requests but I failed to do so after trying it a few times. I also tried to set req.headers in server side but it didn't do what I wanted to..
I want to set request headers for authentication of the form "Bearer {token}" for every request after token generation. How to do it with JS??
What I am most concerned about is that every tutorial does it with postman but they didn't show how they implemented it in their own app. I hope my question is clear.
You can easily add header on your http request like that
it has been solved here Node.JS: How to send headers with form data using request module
In vanilla nodejs:
const uri = "http://example.com";
const options = {
headers: {
"Authorization": "Bearer ...."
}
}
// require http/https lib
let req = require("http").request(uri, options, (res) => {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.once("end", () => {
// concat body chunks
let body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.on("error", (err) => {
console.log(err);
});
req.end();
https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_http_request_options_callback
Something like that:
$.ajax({
url: url,
beforeSend: function(xhr) {
xhr.setRequestHeader("custom_header", "value");
},
success: function(data) {
}
});
First install jwt and express framework using npm then make a middleware file which will check if the tokek is set or not.
Middleware.js :
let jwt = require('jsonwebtoken');
const config = require('./config.js');
let checkToken = (req, res, next) => {
let token = req.headers['authorization']; // Express headers are auto converted to lowercase
if (token) {
if (token.startsWith('Bearer ')) { // Checks if it contains Bearer
// Remove Bearer from string
token = token.slice(7, token.length); //Separate Bearer and get token
}
jwt.verify(token, config.secret, (err, decoded) => { //Inser the token and verify it.
if (err) {
return res.json({
status: false,
message: 'Token is not valid'
});
} else {
req.decoded = decoded;
next();
}
});
} else {
return res.json({
status: false,
message: 'Access denied! No token provided.'
});
}
};
Next, create a config file which will contain the secrets.
Config js:
module.exports = {
secret: 'worldisfullofdevelopers'
};
Finally, create a token route which will create your token and after that the rest of the calls will be authenticated for that token.
Index.js :
const middleware = require('./middleware');
const jwt = require("jsonwebtoken");
const config = require('./config.js');
//Call token Route
app.use('/token', (req, res, next) => {
//Generate Token
let token = jwt.sign({ username: "test" },
config.secret,
{
expiresIn: '1h' // expires in 1 hours
}
);
//Send Token
res.json({
success: true,
message: 'Authentication successful!',
token: token
});
});
//Add Authentication to all routes
app.use(middleware.checkToken);
//===> All the routes after middleware will be checked for token
app.use('/getUser', (req, res, next) => {;
console.log('do something')
});
If I understand correctly, you want to set the HTTP header on the client, in order to pass an authentication token to the server. I would recommend that you use a library like **axios*.
Using axios, once you receive the toke, set the header for every outgoing communication with the following line of code:
axios.defaults.headers.common['Authorization'] = "Bearer " + token;
This will set the authentication http header to the form you need.
I am working on a Node.js express application using JWT for authentication to access my admin page. I tested my routes with Postman and it works very well, the problem is in client side. I'll simplify my code and my question to make the question very clair.
My question is how can I get redirected to my admin page after the token has been stored locally with localStorage ?
I already try to solve this problem with ajax but the page still the same. I also tried window.location='/admin' but in this one I can't send a header that contain the token.
First my Server Side :
app.get('/admin', verifyToken, function(req, res, next) {
res.render('views/admin');
});
function verifyToken(req, res, next) {
var token = req.headers['access-token'];
if (!token)
return res.status(401).send({ auth: false, message: 'NO TOKEN PROVIDED' });
jwt.verify(token, config.secret_key, function(err, decoded) {
if (err)
return res.status(500).send({ auth: false, message: 'Failed to authenticate token.' });
console.log("Token is valid");
next();
});
}
Client Side :
function login(event) {
event.preventDefault();
let formData = new FormData(event.target);
fetch("/admin/login", {
method: 'POST',
body: formData
}).then(function (response) {
return response.json();
}).then(function (result) {
if (result.auth === true) {
localStorage.token = result.token;
//HERE IS THE PROBLEM
$.ajax({
type : "GET",
url : "/admin",
beforeSend: function(xhr){
xhr.setRequestHeader('access-token', localStorage.token);
},
success : function(result) {
//HERE IS THE PROBLEM
window.location='/admin';
}
});
} else {
console.log("Incorrect username or password.");
}
});
}
So how do I send the token in the headers like I did in Postman in client side and get redirected automatically, is there any method ? Many thanks.
If your admin page is rendered as full page, then just do document.write(result) in /admin ajax request success handler
success : function(result) {
document.write(result)
}
I noticed that using this method isn't a good practice. In my example, making redirect in client side isn't good, it would be better to do it in server side and more than that I used less secure method with localStorage to store my token.
So I told myself why not to do the redirection in my server side and for this I used cookie-parser middleware to check if the cookie created contain my token, if it's true then make a redirection to admin page.
Cookie or localStorage are both not secure, but the cookie is a good option to store my token because web storage does not enforce any secure standards during transfer whether with HTTP or HTTPS.
My Server side
app.get('/admin', verifyToken, function(req, res,next) {
res.render('views/admin');
});
app.get('/admin/login', function(req, res){
if(req.cookies.myToken)//Make redirection
return res.redirect('/admin');
res.render('views/login');
});
function verifyToken(req, res, next) {
var token = req.cookies.myToken;
if (!token)
return res.status(401).send({ auth: false, message: 'No Token Provided!'});
jwt.verify(token, config.secret_key, function(err, decoded) {
if (err)
return res.status(500).send({ auth: false, message: 'Failed to authenticate token.' });
req.userId = decoded.id;
next();
});
}
Client side :
fetch("/admin/login", {
method: 'POST',
body: formData,
credentials: 'include',
}).then(function (response) {
return response.json();
}).then(function (result) {
console.log(result);
if (result.auth === true) {
window.location="/admin";
} else {
console.log("Incorrect username or password.");
}
})
If you work with jwt you have send the token with every request.
Usually this will be done with a framwork like jquery or angular, you use a middleware which adds the token to every request.
Here the sample for jquery.
$.ajaxPrefilter(function( options ) {
if (options.beforeSend) {
options.beforeSend = function (xhr) {
xhr.setRequestHeader('Authorization',
'Bearer'+localStorage.getItem('token'));
}
}
});
If you have that, you can use your code:
function login(event) {
event.preventDefault();
let formData = new FormData(event.target);
fetch("/admin/login", {
method: 'POST',
body: formData
}).then(function (response) {
return response.json();
}).then(function (result) {
if (result.auth === true) {
localStorage.token = result.token;
window.location='/admin';
}
});
} else {
console.log("Incorrect username or password.");
}
});
}
I have a client front end at localhost:1841 and a back end at localhost:9000.
My authentication system use a simple couple username/password that delivers a Json Web Token(jwt).
When my client receives the token, i ask him to save it in the cookie with javascript. But when i make XmlhttpRequest call from my client (:1841) to my server (:9000), there is no cookies in the request. So my server delivers a 401 (behavior is ok).
I know that is normal, none information from the cookies is sent because of the SAME-ORIGIN-POLICY.
I m using extjs 6 as client and node js as server.
What are all the steps to configure in the server side and client side to make this working ?
In server side i have already authorize cors request.
I have heard of httpOnly ? but i don't know how to deal with it?
Call for login from localhost:1841 (extjs client):
Ext.Ajax.request({
url: 'http://localhost:9000/api/users/authenticate/',
method: 'POST',
params: params,
success: function(response){
var text = response.responseText;
var data = Ext.decode(text, true);
if(data.access_token){
me.saveToken(data.access_token);
me.createInterface();
} else {
if(data.message){
Ext.Msg.alert("Bummer", data.message);
} else {
Ext.Msg.alert("Bummer", "Something went wrong.");
}
}
},
Config for cors:
cors = require('cors');
...
...
...
var whitelist = ['http://127.0.0.1:9000', 'http://localhost:8080', 'http://localhost:9000', 'http://127.0.0.1:8080', 'http://localhost:1841', 'http://127.0.0.1:1841']
var corsOptionsDelegate = function (req, callback) {
var corsOptions;
if (whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true } // reflect (enable) the requested origin in the CORS response
}else{
corsOptions = { origin: false } // disable CORS for this request
}
callback(null, corsOptions) // callback expects two parameters: error and options
}
...
module.exports = function(app) {
....
app.use(cors(corsOptionsDelegate));
}
Other call from client:
Ext.ajax.request({
url : 'http://localhost:9000/api/users/'
method : 'POST'
success: function(response){
var text = response.responseText;
var data = Ext.decode(text, true);
...
...
}
},
})
Validation from server:
function isAuthenticated() {
return compose()
// Validate jwt
.use(function (req, res, next) {
....
....
console.log(req.headers.authorization);
validateJwt(req, res, function (err) {
if (err) {
console.log(err.inner.name);
if (err.inner.name === "TokenExpiredError") {
// client have to request token with his refresh_token
return next({"error":err.inner.name});
}
}
next();
});
})
.use(function (req, res, next) {
....
});
});
Edit 1:
I have added Set-Cookie in node and Set-Cookie appears in response headers AND in preview cookies from DevTools. But cookies is not set in browser.
exports.authenticate = function(req, res, next){
User.findOne({
fullName: req.body.username
}, function(err, user) {
....
if (!user) {
res.status(401).json({
success: false,
message: 'Authentication failed. User not found.'
});
} else {
// Check if password matches
if(user.authenticate(req.body.password)){
var access_token = jwt.sign(user, config.secrets.session, {
expiresIn: 60 // in seconds
});
res.cookie('access_token',access_token);
res.status(200).json({
"success": true,
"access_token" : access_token
//token: 'JWT ' + token
});
}else{
....
}
}
});
}
As per you using ExtJS Ajax so you can use defaultXhrHeader property to sending token from client side to sever side.
Firstly as you are calling authenticate request for getting token. Here you can use ExtJS Cookies for set and get token or cookies.
Ext.Ajax.request({
url: 'http://localhost:9000/api/users/authenticate/',
params: params,
method: 'POST',
success: function(response, opts) {
var data = Ext.decode(response.responseText;);
if (data.access_token) {
//Set cookie in our client side using Utility class for setting/reading values from browser cookies.
Ext.util.Cookies.set('access_token', data.access_token);
} else {
if (data.message) {
Ext.Msg.alert("Bummer", data.message);
} else {
Ext.Msg.alert("Bummer", "Something went wrong.");
}
}
},
failure: function(response, opts) {
console.log('server-side failure with status code ' + response.status);
}
});
Now you need to pass same token Ajax request using defaultXhrHeader
Here is example:-
Ext.Ajax.request({
url: 'http://localhost:9000/api/users/',
method: 'POST', //As per method acceptance you can use (GET,PUT,DELETE).
//send cookie sever side using defaultXhrHeader
defaultHeaders: {
'access_token': Ext.util.Cookies.get('access_token'),
'Content-Type': 'application/json;charset=utf-8'
},
success: function(response, opts) {
var data = Ext.decode(response.responseText;);
//Put your logic here.
},
failure: function(response, opts) {
console.log('server-side failure with status code ' + response.status);
}
});
As you using NodeJs in server side so you can get token from header.
Client-side JavaScript can only set cookies for the current origin.
Other origins will have their own set of cookies.
You will need to either:
Set the cookie from the :9000 origin using HTTP or
Pass the data through some other mechanism (such as a value in a POST body).
I'm implementing a skill for Amazon Alexa.I want to determine the user's geolocation, but the http.get request is not working. I tried the request in postman and I get the desired result, but couldn't figure out what could be the problem. The request url should be like this https://api.amazonalexa.com/v1/devices/{deviceId}/settings/address with the Authorization header Authorization: Bearer {token}.
Here is my code
try{
var body = "";
console.log('Authorization ', consentToken);
var response = '';
var options = {
host: 'api.eu.amazonalexa.com',
path: '/v1/devices/'+deviceId+'/settings/address',
port: '443',
headers: {'Authorization': "Bearer "+consentToken},
method: 'GET'
};
https.get(options, function(res) {
console.log('status', res.statusCode);
if (res.statusCode >= 200 && res.statusCode < 400) {
res.on('data', function(data_) { response += data_.toString(); });
res.on('end', function() {
var data = JSON.parse(response);
console.log('data', data);
if (data.length > 0)
userLocation = data;
});
}
}).on('error', function(e) {
console.log("errrrror",e);
}).on('uncaughtException', function (err) {
console.log('uncaughtException',err);
});
}
catch(error) {
console.log('getAndProcessUserLocation',error);
}
I don't know why the https.get is not executed. No error is thrown, but I couldn't get any log from it. I followed the documentation from thr official site
https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/device-address-api
Without seeing the rest of your code, my guess is that you are not indicating to the Alexa request that you are handling it asynchronously, so the session is ending before the request completes.
I want to send AJAX requests using Express. I am running code that looks like the following:
var express = require('express');
var app = express();
app.get('/', function(req, res) {
// here I would like to make an external
// request to another server
});
app.listen(3000);
How would I do this?
You can use request library
var request = require('request');
request('http://localhost:6000', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // Print the body of response.
}
})
You don't need Express to make an outgoing HTTP request. Use the native module for that:
var http = require('http');
var options = {
host: 'example.com',
port: '80',
path: '/path',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length
}
};
var req = http.request(options, function(res) {
// response is here
});
// write the request parameters
req.write('post=data&is=specified&like=this');
req.end();
Since you are simply making a get request I suggest this
https://nodejs.org/api/http.html#http_http_get_options_callback
var http = require('http');
http.get("http://www.google.com/index.html", function(res) {
console.log("Got response: " + res.statusCode);
if(res.statusCode == 200) {
console.log("Got value: " + res.statusMessage);
}
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
That code is from that link