Nodejs middleware for specific requests - node.js

I would like to have the middleware for these routes:
POST /tickets
PUT /tickets/:id
DELETE /tickets/:id
etc...
but currently my middleware executes on every HTTP request made on /tickets and so on:
app.use('/tickets', function(req, res, next) {
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
req.decoded = decoded;
next();
}
});
} else {
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
How could I use this on specific requests?

Express has post/get/delete methods for routing. More at documentation
Your should write middleware function and reuse that at routing.
Example:
function JWTCheckMiddleware(req, res, next) {
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
req.decoded = decoded;
next();
}
});
} else {
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
app.post('/tickets', JWTCheckMiddleware, function createTicket(req, res) {...});
app.put('/tickets/:id', JWTCheckMiddleware, function updateTicket(req, res) {...});
app.delete('/tickets/:id', JWTCheckMiddleware, function removeTicket(req, res) {...});

Related

Refreshing JWT access token with refresh token within single middleware function on a post route

I'm trying to learn JWT authentication in express and one thing that I'm came across this code from Github
that this guy has initialised an middleware function to authenticate and check expiry of access token as per below:
app.post("/protected", auth, (req, res) => {
return res.json({ message: "Protected content!" });
})
async function auth(req, res, next) {
let token = req.headers["authorization"];
token = token.split(" ")[1]; //Access token
jwt.verify(token, "access", async (err, user) => {
if (user) {
req.user = user;
next();
} else if (err.message === "jwt expired") {
return res.json({
success: false,
message: "Access token expired"
});
} else {
console.log(err);
return res
.status(403)
.json({ err, message: "User not authenticated" });
}
});
}
and a separate route for refreshing the access token with the help of refresh token
app.post("/refresh", (req, res, next) => {
const refreshToken = req.body.token;
if (!refreshToken || !refreshTokens.includes(refreshToken)) {
return res.json({ message: "Refresh token not found, login again" });
}
// If the refresh token is valid, create a new accessToken and return it.
jwt.verify(refreshToken, "refresh", (err, user) => {
if (!err) {
const accessToken = jwt.sign({ username: user.name }, "access", {
expiresIn: "20s"
});
return res.json({ success: true, accessToken });
} else {
return res.json({
success: false,
message: "Invalid refresh token"
});
}
});
});
So, my question is how secure it is and how can I create single middleware function that could do both authentication and refreshing access token without hitting the app.post('/refresh') as in my view it wouldn't be a smooth experience to deal with it in frontend API management within react
Edit
My middleware seems to work well but it doesn't identify the wrong refresh token and then actually getting worked on protected route
app.post('/home', authenticateUser, (req, res) => {
res.send('welcome');
});
async function authenticateUser(req, res, next) {
let token = req.headers['authorization'];
token = token.split(' ')[1];
jwt.verify(token, JWT_AUTH_TOKEN, async (err, phone) => {
if (phone) {
req.phone = phone;
next();
} else if (err) {
const refreshToken = req.body.refreshToken;
if (!refreshToken || !refreshTokens.includes(refreshToken)) {
return res.json({ message: 'Refresh token not found, login again' });
} else {
jwt.verify(refreshToken, JWT_REFRESH_TOKEN, (err, phone) => {
if (!err) {
const accessToken = jwt.sign({ phone }, JWT_AUTH_TOKEN, { expiresIn: '30s' });
return res.json({ success: true, accessToken });
} else {
return res.json({
success: false,
message: 'Invalid refresh token'
});
}
next();
});
}
} else {
console.log(err);
return res.status(403).json({ err, message: 'User not authenticated' });
}
});
}

how to get the json of a route without fetch

l have a route which return me a json with user grant.
router.get('/test', function(req, res,next ) {
var token = req.cookies.auth;
if (!token) return res.status(401).send({ message: ""});
jwt.verify(token, config.secret, function(err, decoded) {
if (err) return res.status(500).send({ message: "Failed to authenticate token."});
User.findById(decoded.id,function(err,user){
if (err) return res.status(500).send({ message: "problmes found user, sorry "});
if(!user) return res.status(404).send({message: "user not found "});
res.status(200).send({message:user.role});
});
});
});
i want to catch the json response in a variable for another route to authorize an action.
router.get('/', function(req, res, next) {
if (jsonresponse == grant ){
var allMusique;
var idMaxMusique;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("projet_node");
dbo.collection("musiques").find({}).toArray(function(err, result) {
if (err) throw err;
allMusique = result;
var size = allMusique.length-1;
idMaxMusique = parseInt(result[size].id)+1;
res.render('musiques', { resultat: allMusique, idMax: idMaxMusique });
});
});}
else{
res.render('unauthorized');
}
});
create Controllers/middlewares/authenticate.js file and write the below code
const jwt = require('jsonwebtoken')
module.exports = (req, res, next) => {
const token = req.headers['token'] || req.body.token || req.cookies.token;
if (token) {
try {
req.decoded = jwt.verify(token, JWT_SECRET_KEY)
// JWT_SECRET_KEY -> config.secret
next()
} catch (err) {
res.status(403)
.send({ success: false, message: 'Failed to authenticate token.' })
}
}
return res.status(403).send({
success: false,
message: 'No token provided.'
})
}
create Controlller/UserController.js file
exports.getUser = function (req, res) {
// Perform Your requirement of code
// return Something
}
exports.getUserTest = function (req, res) {
// Perform Your requirement of code
// return Something
}
In Your routes/routes.js file
const authenticate = require('./Controllers/middlewares/authenticate');
const UserController = require('./Controllers/UserController');
// Routes with authentication. User must be login for get this routes
router.get('/getUser', authenticate, UserController.getUser);
// Routes without authentication. No need to login
router.post('/getUserTest', UserController.getUserTest);
Most Important require('PathOfFile') properly or Simply always double check path of file and folder in require.

How to exclude a router/api url from jsonwebtoken

I am using node.js express app. jsonwebtoken for authentication. I want to exlude some api url from the jsonwebtoken verification. below is what I have tried and my code
router.use('/authentication', mountAllRoutes(authenticationModule));
// route middleware to verify a token
router.use((req, res, next) => {
const r = req;
const token = req.body.token || req.query.token || req.headers.authorization;
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, (req.app.get('superSecret')), (err, decoded) => {
if (err) {
// res.json({ success: false, message: 'Failed to authenticate token.' });
res.status(401).send({
success: false,
message: 'Failed to authenticate token.'
});
} else {
// if everything is good, save to request for use in other routes
r.decoded = decoded;
next();
// console.log(decoded);
}
return {};
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
return {};
});
router.use('/test', mountAllRoutes(testModule));
router.use('/other', mountAllRoutes(otherModule));
router.use('/data', mountAllRoutes(dataModule));
Here I have placed routes above middleware which I dont want to protect. and I have placed after middleware which I want to protect. But it is protected which I placed above middleware. In authenticationModule, login and user registration api comes. so for user registration it gives response no token provided
Note: I have refrerred this link How-to-ignore-some-request-type-in-Jsonwebtoken
create separate route file for the API you want to exclued.
//Routes
var users = require('./routes/users');
var api = require('./routes/publicApi');
App.js:
// route middleware to verify a token
router.use((req, res, next) => {
const r = req;
const token = req.body.token || req.query.token || req.headers.authorization;
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, (req.app.get('superSecret')), (err, decoded) => {
if (err) {
// res.json({ success: false, message: 'Failed to authenticate token.' });
res.status(401).send({
success: false,
message: 'Failed to authenticate token.'
});
} else {
// if everything is good, save to request for use in other routes
r.decoded = decoded;
next();
// console.log(decoded);
}
return {};
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
return {};
});
app.use('/users', router);//will use Token Authentican
app.use('/publicApi', router);//Dont do this.

Express: call a middleware from another middleware

I'm new to Express 4 and i'm wondering something about how to implement this thing: I'm using jwt to authenticate the consumer of my API, to do that i have a pretty simple middleware to check the validity of the jwt token:
var requireValidToken = function(req, res, next) {
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
try {
var decoded = jwt.verify(token, req.app.get('superSecret'));
} catch(err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
}
req.user = decoded.user;
next();
} else {
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
};
This is working pretty well, but now, i want to extend this to be able to check the role of the user:
router.get('/anAdminRoute', requireRole('ROLE_ADMIN'), function (req, res, next) {
// some code...
});
So i added a middleware for this:
var requireRole = function(role) {
return function(req, res, next){
// Dummy tests...
if(req.user.role == roles.admin || req.user.role == role){
next();
} else {
return res.status(403)({
success: false,
message: "Token valid, but you don't have the right permission to access this resource :)"
});
}
}
}
But as this requireRole() function while obviously checks for a valid jwt token, i'm wondering how can i call my requireValidToken middleware within this function, and so not having to explicitly call it for each route i want to protect.
An easy solution would have been not to use requireValidToken as a middleware but i still want to be able to use it to protect certain routes
Edit: Solution
Chaining middlewares is a simple as that:
var middleware2 = function(param) {
return function(req, res, next){
middleware1(req, res, function(){
// middleware2 code
});
}
}
If anybody interested, my final working solution to validate a user role:
var jwt = require('jsonwebtoken'),
roles = require('../models/user').roles;
// authentication middleware
// check if the given jwt token is valid
var requireValidToken = function(req, res, next) {
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
try {
var decoded = jwt.verify(token, req.app.get('superSecret'));
} catch(err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
}
req.user = decoded.user;
next();
} else {
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
};
var requireRole = function(role) {
return function(req, res, next){
requireValidToken(req, res, function(){
if(req.user.role == roles.admin || req.user.role == role){
next();
} else {
return res.status(403).send({
success: false,
message: "Token valid, but you don't have the right permission to access this resource :)"
});
}
});
}
}
module.exports = {
requireValidToken: requireValidToken,
requireRole: requireRole
}
Completely misread your question. If you want to call requireValidToken for certain situations, you can pass along the req and res objects to the middleware function, along with an anonymous callback. How you get the middleware function largely depends on your application architecture so I'll assume I have the requireValidToken within my context:
var requireRole = function(role) {
return function(req, res, next){
// Dummy tests...
requireValidToken(req, res, function () {
if(req.user.role == roles.admin || req.user.role == role){
next();
} else {
return res.status(403)({
success: false,
message: "Token valid, but you don't have the right permission to access this resource :)"
});
}
});
}
};
This syntax worked for me. Where auth is another middleware module
import auth from "../middlewares/auth.js";
export default function (req, res, next) {
auth(req, res, function () {
if (req.params.id !== req.user._id)
return res
.status(401)
.send({ status: "error", message: "User does not have rights to modify this data." });
next();
});
}

ExpressJS: How to mock request handler next function with mocha

I have an handler
public ensureAuthenticated(req: express.Request, res: express.Response, next: Function) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.param('token') || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, config.secret, function(err, decoded) {
if (err) {
return res.status(404).json({ success: false, message: 'Failed to authenticate token.' });
} else {
// if everything is good, save to request for use in other routes
next();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
}
And here the route
app.post('/api/article/create', AuthenticationHelper.ensureAuthenticated, this.create);
In unit test, how can I mock the ensureAuthenticated to make sure it is authenticated.
sinon.stub(AuthenticationHelper, 'ensureAuthenticated').returns(true);
I will give you an example where I test it without using sinon.
This is my authentication-helper.js:
'use strict';
module.exports = function(jwt, config) {
return {
ensureAuthenticated: function (req, res, next) {
var token = req.body.token ||
req.param('token') ||
req.headers['x-access-token'];
if (token) {
jwt.verify(
token,
config.secret,
function(err, decoded) {
if (err) {
res
.status(404)
.json({
success: false,
message: 'Failed to auth.'
});
} else {
next();
}
}
);
} else {
res
.status(403)
.send({
success: false,
message: 'No token provided.'
});
}
}
};
}
And this is my test file:
'use strict';
var jwt = {};
jwt.verify = function (token, secret, fn) {
fn(null, 'something');
};
var config = {};
config.secret = 'shh';
var req = {};
req.body = {};
req.body.token = 'mytoken';
var res = {};
var AuthenticationHelper = require('./authentication-helper.js')(jwt, config);
describe('Test Express Middleware', function() {
it('should call next on middlware', function(done) {
var next = function () {
console.log('next was called');
done();
};
AuthenticationHelper.ensureAuthenticated(req, res, next);
});
});

Resources