Is it possible to use validation with express static routes? - node.js

I'm using jwt token validation in my project to protect some importent data:
if (req.headers.auth) {
var token = req.headers.auth.split(' ')[5];
var payload = jwt.decode(token, 'blablabla...');
if (!payload.sub) {
res.status(401).send({
message: 'Authentication failed'
});
}
if (!req.headers.auth) {
return res.status(301).send({
message:'You are not authorized'
});
}
res.send(data);
} else {
res.header(404).send('Go away!');
}
Is it possible to use this method to protect the static rout, added using express static middleware?
UPDATE!!!
Ok, now jwt token validation set on my static route. But I have got another problem - how to send this token to node.js server BEFORE my angular app uploaded (beacose now it is blocked with new middleware) and started to insert tokens in to the http headers. Do I need some extra module, or maby my new middleware can request somehow that jwt token from the browser?

Yes, you can attach an extra middleware to execute for your express static resources like this:
var staticMiddleware = function(req, res, next) {
console.log('Hello from staticMiddleware!');
next();
};
app.use(staticMiddleware, express.static(__dirname + '/public'));
Note that if you do add this JWT token checking middleware you should only be returning a response in this code (eg res.send()) if authentication fails. If the JWT is valid, to allow the code to proceed to the static route, call next().
I would have two additional notes regarding your code:
Your if(!req.headers.auth) block will never be executed, you're already in side an if(req.headers.auth) block.
In all failure cases here (req.headers.auth is missing, or payload.sub is missing) you should return a 401 Unauthorized. 301 and 404 would both be incorrect.

Related

Why is my authenticated NodeJS route returning results with an incorrect JWT token?

I have a NodeJS application which I have begun to separate out in to smaller files since the original became a little bloated.
In my index.js I have routes that are protected by a function a freelancer wrote to provide JWT authentication. These routes work as required.
app.use(require('./lib/api-calls/convert.js'));
// Security Enabled index.js
//
const { app } = require ('./lib/deps/init_dependencies.js');
const { enableSecurity } = require("./security");
const main = async () => {
// Enable API JWT Security = Comment out the line below to turn off security.
await enableSecurity(app);
app.get('/v1/createSession:key/:limit', function (req, apiResponse) {
// My route, working well
});
}
main()
I've created /lib/routes/convert.js and am wanting to write new routes in this file which also require JWT authentication. However, I always receive status 200 'OK', regardless of whether the authentication header is correct or not... I'm using Postman to make my calls. Here's my code:
const app = require('express')();
//JWT authentication
const { enableSecurity } = require('../../security');
const main = async () => {
// Enable API JWT Security = Comment out the line below to turn off security.
await enableSecurity(app);
app.get('/v3/convertw3w/:locationValue/:countryCode', function (req, res) {
res.status(200).send({ status: 'OK' });
});
}
main()
module.exports = app;
Can anyone spot the problem? I spent far to long on this last night!
thanks
Just some food for thought here and we do something similar, but if you use
enableSecurity(app)
As middleware on the route and the
next()
function in the middleware you can omit the need to make this a promise, because middelware is designed to process in order of the middleware and the next function tells express to move to the next middleware.
How we do it, is to have the middleware 'auth', because middleware will pass the req and res objects to each one in the stack you can have all your JWT decode in one place.
We typically will pass the token in the header OR the req object, just depends on the mimetype we pass, so in out auth we check if the token is in the header or the req, if so we decode, if it passes decode we pass
next()
in that code block otherwise we res.json({"response":"not authorized"})

How to terminate route middleware chain?

I have a simple Express router setup with authentication middleware. I have something like the code below.
If the user navigates to '/authenticate' with improper credentials, I want the middleware to send an error response and all middleware and route processing to cease. To do that, I sent a response, told Express to skip the rest of the route middleware with next('route'), and included a return to stop processing the authMiddleware function.
let router = express.Router()
function authMiddleware(req, res) {
//Do some authentication checks
if(!authenticated) {
res.status(403).send("Could not authenticate. :-(")
next('route')
return
}
//Additional authentication checks
}
router.use(authMiddleware)
router.post('/authenticate', (req, res)=> {
res.send("You should not see me if you aren't authenticated!")
}
I would expect the post route not to run; however, it does, giving me the error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client. I have searched Google, Stack Overflow, and the Express docs to no avail, though perhaps my search terms are lacking.
I saw a Scotch article that suggested doing a redirect, but that seems a little hacky and inelegant.
So my question: What is the proper way to terminate a middleware/routing chain?
To terminate the middelware and route chain, simply do not calling the next().
function authMiddleware(req, res, next) {
let authenticated = false;
if(!authenticated) {
res.status(403).send("Could not authenticate. :-(");
// do not call next(), and simply return
return;
}
//Additional authentication checks
// all passed, let's pass it to next()
next();
}

Authentication in Express Middleware

I'm a little new to this. I have REST API made with Node.js and Express.js. Some routes have authentication middleware. To use those routes, a header has to be set with the user's auth token which gets verified. I have been doing this with no problem with static sites using local storage. I'm making my first dynamic site now (using Express) and for certain routes I have middleware that loads all the data I need to display the page. How do I access and use auth tokens now that I don't have local storage's help?
EDIT(for clarification):
So here is one of my api routes that fetches all transactions from a database(mongoDB).
app.get('/transactions', authenticate, (req, res) => {
Transaction.find().then((transaction) => {
res.send({transaction});
}, (e) => {
res.status(400).send();
});
});
This is the authentication middleware that gets run.
var authenticate = (req, res, next) => {
var token = req.header('x-auth');
User.findByToken(token).then((user) => {
if (!user) {
return Promise.reject();
}
req.user = user;
req.token = token;
next();
}).catch((e) => {
res.status(401).send();
});
};
Now on my express webserver, I have a following route, where I use getTransactions to fetch all my data. (which I display with handlebars)
router.get('/orders', getTransactions, (req, res) => {
res.render('orders.hbs', {
transaction: req.transactions.data.transaction
});
});
and this is the middleware
var getTransactions = (req, res, next) => {
axios.get('https://serene-wave-28270.herokuapp.com/transactions')
.then((response) => {
req.transactions = response;
console.log(req.transactions.data.transaction);
next();
}).catch((e) => {
console.log(e);
})
}
So when I was just making a static site without using express as a webserver, I would just have the user sign in and save the auth token in local storage. Also, I should note that the first two blocks are from my api, and the bottom two from webserver, both hosted separately on Heroku. I'm not sure if that's standard design so I thought I should mention it.
There's not a whole lot of detail in your question for exactly what you're trying to do, but I can explain the general concepts available to you in Express:
The usual scheme for Express is to authenticate the user initially and then set a session cookie that indicates that user has been authenticated. Since the cookie is automatically stored by the browser and then automatically sent from the browser to the server with every request, you will have that cookie which the server can then use to identify a server-side session and then you can use any info you want from the session (user identify or other state you store in the session object) when creating pages or responding to API requests for that user.
The NPM module express-session handles much of this work for you as it will automatically create a session object, a session cookie and hook the two together on every request.
If, on the other hand, you already have an auth token in the client and you just want that to be automatically communicated to the server with every request, then you can just put that auth token into a cookie and have the server look for it in the cookie on each request. You can even make it a bit more secure by setting the cookie to HttpOnly so that the auth token cannot be accessed from client-side Javascript (this will not affect the server's ability to access it).
There is not much detail in your question but here are a few thoughts.
You can either use cookies (as detailed by #jfriend00 below) or use the requests' headers to check for a valid authorization token (which I describe below)
In Express you can access the headers through req.headers so you can just write a middleware that you will call before your current middleware loading all the data to ensure that the user is authorized to continue (calling next() to call the next middleware) or using a custom Error type to flag the authentication error if he is not (calling next(err) to skip all the other middleware and jump to your error middleware)
For example (assuming you have a subclass of Error named AuthorizationError defined somewhere):
const express = require('express');
const AuthorizaztionError = require('<some path>');
const app = express();
function checkAuthTokenMiddleware(req, res, next) {
if (req.headers && req.headers.authorization) {
let token;
const parts = req.headers.authorization.split(' ');
if (parts.length == 2) {
const [scheme, credentials] = parts;
if (/^Bearer$/i.test(scheme)) { // or any other scheme you are using
token = credentials;
}
if (token === undefined) {
// access token - missing
return next(new AuthorizationError(
"Invalid access token.", // error_description
"invalid_token" // error
));
}
// add something here to ensure the token is valid
return next();
}
} else {
// No authorization header => invalid credentials
return next(new AuthorizationError(
"Authorization header required.", // error_description
"invalid_request" // error
));
}
}
// Add this in your route declaration
app.use(
"/auth/test",
checkAuthTokenMiddleware,
function(req, res, next) {
// do something
}
);
// this must come last
app.use(function errorMiddleware(err, req, res, next) {
// return something
if (err instanceof AuthenticationError) {
// do something for example
res.status(401).send(err.error_description);
} else {
// generic error handling, for example
res.status(500).send("Error "+err);
}
})
// ...

Generate test session manually with express-session

I have implemented the OAUth 2.0 flow as single authentication method for my express application.
In real situation, once a user connected using OAuth, a session is created and accessible server-side in req.session.passport.
In this session, there is the OAuth access token that is required to perform authenticated requests on my REST API. To be able to do so, I wrote a middleware that copies the token from req.session.passport to the Authorization header.
app.use(function(req, res, next) {
if (req.session.passport) {
req.headers['Authorization'] = req.session.passport.user.accessToken;
}
next();
});
Now, I would like to test this middleware without going through the entire oauth flow. Ideally, I would like to create a session manually and inject test data inside req.session.passport, then call any protected endpoint of my API to check that it can correctly perform authenticated requests.
I tried to manually set data inside req.session in the following test
it('Should be able to make an authenticated request with session data',
function(done) {
var req = request(app).get('/api/SomeProtectedEndpoint');
req.session = {
passport: {
user: {
accessToken : 'eade123d3ffwhatever'
}
}
}
req.expect(200, function(err, res){
if (err) return done(err);
done();
});
});
But if I display the contents of req.session inside my middleware, the manual data is gone. I believe it is removed by express-session.
How can I manually inject session data in a request for testing purposes ?

Correct way to call passport js function from react component

Hello I am new to react and Nodejs. Currently I am trying to make a login component in react which contains a button through which app can authenticate the user through Facebook. I am using passport.js for authentication. I am also using reflux for handling any api call to node server.
Below is the respective code for each
actions.js
var Reflux = require('reflux');
module.exports = Reflux.createActions([
"facebookLogin"
]);
store.js
var Reflux = require('reflux');
var Actions = require('../actions');
var Api = require('../utils/api');
module.exports = Reflux.createStore({
listenables: [Actions],
facebookLogin: function(email) {
Api.FBrequest(email)
.then(function(response){
console.log('returned user for facebook from server : ' + response);
}.bind(this));
}
});
api.js
module.exports = {
FBrequest: function() {
return (
fetch('/auth/facebook', {
method: 'get'
}).then(function(response){
return response.json();
})
);
}
};
facebook.js
// file at server for handling passport authentication calls
module.exports = function(app, passport){
// call to facebook for authenticating user
// in response to this call, facebook will reply in /auth/facebook/callback with the user object
app.get('/auth/facebook', passport.authenticate('facebook', {scope:'email'}));
// TODO return error on failure of login instead of navigating to the login route
app.get('/auth/facebook/callback', passport.authenticate('facebook',
{failureRedirect: '/login'}), function(req, res){
// user successfully authenticated by facebook
// return the user object
return req.user;
});
};
When I click the fbLogin button on my app I get the following error
Fetch API cannot load https://www.facebook.com/v2.2/dialog/oauth?response_type=code&redirect_uri=…3A3000%2Fauth%2Ffacebook%2Fcallback&scope=email&client_id=1807765906116990. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I want to know that is it correct approach to use fetch for directly sending the get to server for '/auth/facebook' and let the server handle the request and return with user object. If it is then where this is going wrong ? If it is not then what is the correct approach for achieving the same with react?
For anyone else who stumbles upon this question like I did tonight - we solved this error by having the login button wrapped in an a href tag - which then takes the user to our authorization route. Once the user is authorized, facebook then returns the user to us. Then, every time our component mounts, we make sure the state has our logged in user mounted. If it doesn't we make a get request via axios to a route which passes back the user object, and we set our state appropriately.

Resources