skip token verification for GET request - node.js

I want skip token verification for GET method in express. I want to allow GET request for everyone while just post, put, delete request by authorized user.below is my logic but the response hanging. I tried to used nested express use method.
app.use(function(req, res, next) {
if (req.method === 'GET') {
app.use('/api/someroute', routes);
}
else{
//do verification below the next
next();
}
})
or is there any other way to handle this

Just include a middleware on desired routes :
var router = express.Router();
// no middleware included for get request
router.get("/route1", handlerRoute1);
router.get("/route2", handlerRoute2);
// include some middleware
router.post("/route3", myMiddleware1, myMiddleware2, handlerRoute3);
app.use(router);
Where myMiddleware1 and myMiddleware2 looks like :
myMiddleware1 = function(req, res, next){
// verify token, etc, ....
var success = true;
// call next on success
if(success)
return next();
else
{
// raise error
return res.status(500).json({error: "Missing token..."});
}
};

It's because in the scenario for GET requests you don't actually complete the request (or move on from that middleware). Middleware is processed in sequential order i.e. first come first served. If you only want to protect everything other than GET requests then something like this would be fine:
app.use(function(req, res, next) {
// let GET requests through
if (req.method === 'GET') return next();
// perform token auth on all other requests, next() if OK
});
// setup routes
app.use('/api/someroute', routes);
You would setup your middleware first then declare your routes after, this means any requests coming in will have to pass through your token check, in this case you just skip GET requests.

Related

Nodejs express res.redirect loop

Using Nodejs and an Express server I'm trying to prevent anyone from reaching my second set of routes without logging in and while this works I get stuck in a redirect loop if the session doesn't detect the email in the session token. I believe its trying to check for the req.session.email for the /users endpoint as well causing the redirect loop but as the session checking middleware is used after I thought the /users endpoints would avoid the check.
How can I organize my code so that the books endpoints can only be reached when the req.session.email is satisfied and also not get stuck in a redirect loop when someone tries to reach it without being logged in?
app.use('/users', users)
app.use((req, res, next) => {
if(!req.session.email){
res.redirect('/login')
}
else{
next();
}
})
app.use('/books', books);
The order of the app.use statements is not really important in this case; You could add your middleware to the route-level if you're only checking the /books endpoint.
const yourMiddlewareFunction = (req, res, next) => {
if(!req.session.email){
res.redirect('/login')
}
else{
next();
}
}
app.use('/books', yourMiddlewareFunction, books);
If you only want to protect the /books endpoints, you can do it like this :
function requireLogin(req, res, next) {
if(!req.session.email){
res.redirect('/login')
}
else{
next();
}
}
app.use('/books', requireLogin, books);

How to apply instance of use() to all routes except those handed by app.use(express.static("dist"))?

I think I have resolved this issue in the process of writing it, basically the solution seems to be:
Move the static file handler above the other instance of use()
Confirmation that this is an acceptable approach would be appreciated though and perhaps help others in a similar scenario.
Desired Behaviour
Apply a use() instance to all routes except those handled by:
app.use(express.static("dist"));
Actual Behaviour
use() is being applied to all routes, including those handled by:
app.use(express.static("dist"));
Scenario
For securing access to API's, I am using the model described in this Lynda.com tutorial:
Node.js: Securing RESTful APIs
In pseudo code, the model is essentially comprised of:
a global use() instance that checks if a jwt token has been sent
if a token has been sent, if verifies the token
it sets the req.user property to undefined if verification fails or a token wasn't sent
otherwise, it sets the req.user property to the decoded jwt value if verification succeeds
subsequent middleware performs conditional behaviour based on the value of req.user
This model is working well for all intents and purposes.
However, I recently added some console logging and can see that verification is being performed for both:
api requests (desired behaviour)
static files served via app.use(express.static("dist")) per this convention (undesired behaviour)
Question
How can I apply the verification use() instance to all routes, except those handled by app.use(express.static("dist")).
What I've Tried
I think I have resolved this issue by moving section 2 of the code below above section 1.
// 01. verification use() called on all requests
app.use((req, res, next) => {
// if jwt authorisation has been sent in headers, verify it
if (req.headers && req.headers.authorization && req.headers.authorization.split(' ')[0] === 'JWT') {
console.log("jwt verification sent, verifying...");
try {
// this is synchronous as it has no callback
req.user = jsonwebtoken.verify(req.headers.authorization.split(' ')[1], 'RESTFULAPIs');
console.log("jwt verified, will return decoded value");
} catch (err) {
req.user = undefined;
console.log("jwt verification failed, user will remain undefined: " + err);
}
// move to the next piece of middleware
next();
}
// if jwt authorisation has not been sent in headers
else {
console.log("jwt verification not sent, leaving user as undefined");
console.log(req.originalUrl);
req.user = undefined;
// move to the next piece of middleware
next();
}
});
// 02. use() for serving static files
app.use(express.static("dist"));
// 03. middleware to check if login has been verified
const api_login_required = (req, res, next) => {
// if token verification was successful and the user property exists
if (req.user) {
// move to the next piece of middleware
next();
}
// otherwise, return unauthorised user message
else {
res.json({ verification: 0 });
}
}
// 04. middleware called in route handlers
app.route("/api/:api_version/users/private_data")
.get(api_login_required, api_users_private_data_get)
.post(api_login_required, api_users_private_data_post);
Middleware always controls the flow from to button in which order they wrote. Like
if (example 1)code like
app.use((req,res, next)=>{// middleware 1; next()} )
app.get('/rot1', (req, res)=> res.status(200).send('route 1'));
app.get('/rot2', (req, res)=> res.status(200).send('route 2'));
In this case, middleware appears in both route1, route because of middleware set at the top of the route.
If (example 2)code like
app.use((req,res, next)=>{// middleware 1; next()} )
app.get('/rot1', (req, res)=> res.status(200).send('route 1'));
app.use((req,res, next)=>{// middleware 2; next()} )
app.get('/rot2', (req, res)=> res.status(200).send('route 2'));
Here middleware1 applied in both route1 and route 2
But middleware2 applied only on route2.
But you can also define specific middleware for each route
function middleware1(req, res, next){
next();
}
function middleware2(req, res, next){
next();
}
app.get('/rot1', middleware1, (req, res)=> res.status(200).send('route 1'));
app.get('/rot2', middleware2, (req, res)=> res.status(200).send('route 2'));
Here middleware1 only applied on route1 and middleware2 only applied on route2.
Maybe above explanation help you!!

Add header to all responses after processing but before sending to client

I have two endpoints in a node js app:
app.get('search', myGetController);
app.post('add', myPostController);
For simplicity, let's assume both services have only the following code:
exports.myGetController = function(req, res) {
res.status(404).json({ error: "not found" });
};
I want to have a middleware that is executed after the processing of the controllers, but before they are sent to the browser, so I can add a header based on the body of the response.
// process all responses to add ed25519
app.use(function(req, res, next) {
res.setHeader('CharCount', [How To get Body content]);
next();
});
I have two questions:
First of all, I would like to have all my controllers pass by that middleware after processing.
Second, I would like to access the body content so I can generate a header based on its content.
UPDATE
I have tried the suggested answer someone posted, and it is not working, or I am missing something.
This is what I have (before setting up my routes):
app.use(function(req, res, next) {
const oldResJson = res.json;
res.json = function(body) {
res.setHeader('myToken', generateHeaderBasedOnBody(oldResJson));
oldResJson.call(res, body);
}
next();
});
The response that is being passed to my method is an empty string, even though the response sent by the service is not empty. Am I doing this in the wrong place, or what am I missing?
One solution for this issue would be to override the res.json function like so:
// process all responses to add ed25519
app.use(function(req, res, next) {
const oldResJson = res.json;
res.json = function(body) {
res.setHeader('CharCount', /* Use body here */);
oldResJson.call(res, body);
}
next();
});
By doing this, you don't even need to change your controllers.

Express.js middleware executing for a route defined above it

From what I have read here and here, the order in which you place your middleware function matters, as you can have certain routes not go through the middleware function if it is placed before the route, and the routes which are placed after will go through this middleware function.
I am seeing mixed results as my dev environment is not respecting this and my prod environment is. The code is exactly the same.
What I am trying to do is have my login route not be protected by a token checker middleware function and have the rest of my routes protected by a token.
Here is my code:
routes.get('/login', function(req, res) {
// login user, get token
});
routes.use(function(req, res, next) {
// check header or url parameters or post parameters for token
var token = req.headers['access-token'];
// decode token
if (token) {
// validate token
}
else if (req.method === 'OPTIONS') {
next();
}
else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
routes.get('/query/:keywords', function(req, res) {
console.log(req.params.keywords);
// execute query
});
app.use('/', routes);
the /query route is the only one that should have to go through the token middleware function correct? Right now I am getting the /login route also going through the token middleware function, which doesn't make sense as I shouldn't need to have a token to login.
Better yet, if there is a way to target which routes I want protected and which routes I do not want protected, this seems better than having to rely on an "order" of where the middleware function is placed.
First, follow along this usage in ExpressJS:
More than one callback function can handle a route (make sure you specify the next object). For example:
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res) {
res.send('Hello from B!')
})
You'll notice it's definition is close to what you're declaring on routes.use(yourFunction(...)). However, there's no real reason to do it this way other than following examples you've seen in documentation, which is a good way to start nevertheless.
However, it's a flimsy implementation, express will allow hierarchies within it's .get() .post() methods, that's correct, but this is a use case specific and not what you're looking for.
What you need is to implement your custom auth process using the double callback configuration. do this:
// You can save this function in a separate file and import it with require() if you want
const tokenCheck = function(req, res, next) {
// check header or url parameters or post parameters for token
var token = req.headers['access-token'];
// decode token
if (token) {
// validate token
}
else if (req.method === 'OPTIONS') {
next();
}
else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
routes.get('/login', function(req, res) {
// login user, get token [Unprotected]
});
routes.get('/query/:keywords', tokenCheck, function(req, res) {
console.log(req.params.keywords);
// execute query [Protected with tokenCheck]
});
app.use('/', routes);
You might need to play around with the code above, but it'll guide you on the right direction, this way, you can specify particular routes to execute the tokenCheck(req, res, next) function as you want.
The easiest way to do this is to use Router Middleware to scope Routes that require Authentication and the routes that don't. Since all Routers are Middleware, we can implement them just like any other middleware. Ensuring that we place the Routers and Routes in the order that we would like our Routes to be evaluated.
In the below example, the Express server has 2 routers, a LoginRouter and an ApiRouter.
LoginRouter - Generates a Token when receiving a request to POST /login and returns that to the requester for subsequent use in the /api routes.
ApiRouter - Wraps all other routers, centralizes middleware that needs to be globally applied to all routes under /api. Is only accessible to Authenticated Requests.
The API Router is only accessible if there is a token included in the Header and that token is obtained from the LoginRouter. LoginRouter has no authentication required.
With this setup, you'll keep adding routers after the Authorization Middleware to the API Router via .use() on the ApiRouter.
The below pattern of composing Routers from other Routers is very powerful, scalable and easy to maintain.
server.js
const express = require('express')
const bodyParser = require('bodyParser')
const ApiRouter = require('./routes/api')
const LoginRouter = require('./routes/login')
const port = process.env.PORT || 1337
const server = express()
server.use(bodyParser.json())
server.use('/login', LoginRouter)
server.use('/api', ApiRouter)
server.listen(port, () => console.log(`Listening on ${port}`))
LoginRouter - /routes/login.js
const router = require('express').Router()
router.post('/', (req, res) => {
// Validate Credentials
// some validation code...
// Then create the token for use later in our API
let token = '...'
// Response 200 OK with the token in the message body
return res.status(200).send({token})
})
module.exports = router
ApiRouter - /routes/api/index.js
const router = require('express').Router()
const UsersRouter = require('./routes/api/users')
router.use((req, res, next) => {
let authorizationHeader = req.headers['authorization'] || req.headers['Authorization'] // handle lowercase
let [, token] = authorizationHeader.split(' ')
if (!token) {
return res.sendStatus(403) // Forbidden, you're not logged in
} else {
// validate the token
if (!tokenIsValid) {
return res.sendStatus(403) // Forbidden, invalid token
}
// Everything is good, continue to the next middleware
return next()
}
})
router.use('/users', UsersRouter)
module.exports = router
UsersRouter - /routes/api/users
const router = require('express').Router()
router.get('/', (req, res) => {
// We only get here if the user is logged in
return res.status(200).json({users: []})
})
module.exports = router
The application of the token middleware should not happen to the login route due to route order and the fact the login route never calls the next object. Without more information we really can't trouble shoot what is happening beyond that however you could try inspecting it in your dev environment with a debugger break and looking at the req that hits that middleware.
We can however give you some information on how to try and isolate your .use middleware and how application of middleware order applies so that you can try and separate it from the login route entirely like in the bottom of your question.
When applying middleware to only specific routes you should keep note that order and .use are for middleware that should answer the request before telling express to continue looking for other middleware that come after them in the router that will also handle the request. If you only want it on a few routes, you can add it to only a few routes by being explicit like so:
router.get('/route', [ middleware1, middleware2, ..., middlewareX])
or
router.get('/route', middleware1, middleware2, ..., middlewareX)
both patterns will work. I however find the array pattern a little more palatable since I can define a lot of middle wares I want to apply and then concatenate new middleware for specific logic, and I only need modify where I declare that concatenation to add more functionality. It'd however rare to need that many middleware and you should be able to use either.
You could also section that middleware off to a subset of routes by using a router and applying it as the first middleware to the route chain before the router.
app.use('/user', authentication, userRouter)
or you can put it inside the router as the first middleware with a .use so that it handles all requests.
So remember the general tips about middleware usage:
order matters for middleware application
optional middleware that should be applied on route basis should be applied with the other middleware in order for only that route
error handling middleware must always come last, and have four arguments (err, req, res, next)
use routers to section .use middleware to specific routes and sets of routes
You can find more information about it in the expressjs documentation for middleware

Two static directories (public+private) in node.js Express framework

The idea is the follow:
Send the login directory when the user is not authenticated.
Send the app directory one time that the user logs in (in this case, using passport module).
Example:
Not logged:
request: GET /
response: index.html from PATH_login
Logged:
request: GET /
response: index.html from PATH_app
I tried this but it didn't work:
app.use(function(req,res,next){
if ( req.isAuthenticated() )
{
// user is authenticated
return express.static(PATH_app)
}
else
{
// user is not authenticated
return express.static(PATH_login)
}
});
On initialization, you're setting that the middleware function that does the switching should be called for every request.
You should also initialize each of the middleware functions that would be switched between at this time.
At runtime for each request (when the code in the function you pass to app.use gets run), for that switching function to forward to the appropriate middleware, it would call the relevant function:
var appStatic = express.static(PATH_app);
var loginStatic = express.static(PATH_login);
app.use(function(req, res, next) {
if (req.isAuthenticated()) {
// user is authenticated
return appStatic(req, res, next);
} else {
// user is not authenticated
return loginStatic(req, res, next);
}
});

Resources