Unable to Apply Middleware to Router in ExpressJS? - javascript

I have an app where I have public routes and authenticated routes. isAuthenticated were applied for example to a news controller.
globalRouter: function (app) {
app.use((req, res, next) => {
logger.log("Endpoint: ", req.originalUrl);
next();
});
const userRouter = require("./user/controller");
const globalRouter = require("./global/controller");
const newsRouter = require("./news/controller");
app.use("/user", userRouter);
app.use("/global", globalRouter);
app.use("/news", middleware.isAuthenticated(), newsRouter); // here
}
And here is the isAuthenticated code written in middleware.js file.
const security = require("../utils/security");
const service = require("../user/service");
exports.isAuthenticated = function (req, res, next) {
let authorization = req.headers.authorization;
let token = null;
if (authorization.startsWith("Bearer ")) {
token = authorization.substring(7, authorization.length);
if (token !== null) {
service.checkUserTokenMiddleware(token, security).then((response) => {
console.log("checkUserTokenMiddleware", response);
if (response) {
next();
}
});
}
}
};
The problem is that I'm getting this error below when I npm start the app
TypeError: Cannot read property 'headers' of undefined at Object.exports.isAuthenticated
What am I missing here?
why do I get such an error meanwhile in my other file using the same method like req.body.blabla or req.headers.blabla is fine?
Any help will be much appreciated.
Regards.

Simply remove the brackets after the function call:
app.use("/news", middleware.isAuthenticated, newsRouter);
You don't have to call the function in the callback to app.use, Express will itself pass in req,res,next to the auth function and call it.

It depends on how you import, middleware.js. Since you are exporting, isAuthenticated as function. This should be not called before passing to app.use.
Other things to be noticed, you never call the next function on error or else.
Please have a look in the below example.
// middleware.js
const security = require("../utils/security");
const service = require("../user/service");
exports.isAuthenticated = function (req, res, next) {
let authorization = req.headers.authorization;
let token = null;
if (authorization.startsWith("Bearer ")) {
token = authorization.substring(7, authorization.length);
if (token !== null) {
service
.checkUserTokenMiddleware(token, security)
.then((response) => {
if (response) {
next();
}
})
.catch((error) => next(error));
} else {
next("UNAUTHORIZED");
}
} else {
next("UNAUTHORIZED");
}
};
// app.js
const middleware = require("./middleware")
app.use((req, res, next) => {
logger.log("Endpoint: ", req.originalUrl);
next();
});
const userRouter = require("./user/controller");
const globalRouter = require("./global/controller");
const newsRouter = require("./news/controller");
app.use("/user", userRouter);
app.use("/global", globalRouter);
app.use("/news", middleware.isAuthenticated, newsRouter); // here

Related

JWT Authorization is failing for all endpoints

So I am creating a social media application.
I used JWT token for verification on all endpoints. It's giving me custom error of "You are not authorized, Error 401"
For example: Create post is not working:
This is my code for JWT
const jwt = require("jsonwebtoken")
const { createError } = require ("../utils/error.js")
const verifyToken = (req, res,next) => {
const token = req.cookies.access_token
if(!token) {
return next(createError(401,"You are not authenticated!"))
}
jwt.verify(token, process.env.JWT_SECRET, (err,user) => {
if(err) return next(createError(401,"Token is not valid!"))
req.user = user
next()
}
)
}
const verifyUser = (req, res, next) => {
verifyToken(req,res, () => {
if(req.user.id === req.params.id || req.user.isAdmin) {
next()
} else {
return next(createError(402,"You are not authorized!"))
}
})
}
const verifyAdmin = (req, res, next) => {
verifyToken(req, res, next, () => {
if (req.user.isAdmin) {
next();
} else {
return next(createError(403, "You are not authorized!"));
}
});
};
module.exports = {verifyToken, verifyUser, verifyAdmin}
This is my createPost API:
const createPost = async (req, res) => {
const newPost = new Post(req.body);
try {
const savedPost = await newPost.save();
res.status(200).json(savedPost);
} catch (err) {
res.status(500).json(err);
}
}
Now, in my routes files, I have attached these functions with every endpoints.
For example: In my post.js (route file)
//create a post
router.post("/", verifyUser, createPost);
When I try to access it, this is the result
But, when I remove this verify User function from my route file, it works okay.
I have tried to re-login (to generate new cookie) and then try to do this but its still giving me error.
What can be the reason?
P.S: my api/index.js file https://codepaste.xyz/posts/JNhIr9W6zNnN26CH9xWT
After debugging, I found out that req.params.id is undefined in posts routes.
It seems to work for user endpoints since it contains req.params.id
const verifyUser = (req, res, next) => {
verifyToken(req,res, () => {
if(req.user.id === req.params.id || req.user.isAdmin) {
next()
} else {
return next(createError(402,"You are not authorized!"))
}
})
}
So I just replaced === with || and its working. (but its not right)
if(req.user.id || req.params.id || req.user.isAdmin) {
Can anyone tell me the how can I truly apply validation here since in my posts routes i dont have user id in params

Fetch to local server 3001 from local server 3000. Unexpected end of input

I made get request to Serp api, but learned that it is not possible to directly make fetch to Serp from React application, so I created local server and wrote logic for it, then I tested it with Postman and everything is fine. Then I had problems with CORS, I(guess) fixed them, but now I receive rejected promise on response and can't get rid of this. It gives
Unexpected end of input
Here is my server:
const SerpApi = require('google-search-results-nodejs');
const search = new SerpApi.GoogleSearch("myApiKey");
const express = require('express');
const app = express();
var allowCrossDomain = function (req, res, next) {
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}
app.get('/:id', function (req, res) {
console.log("Made request");
const searchText = req.params.id;
const params = {
q: searchText,
tbm: "shop",
};
const callback = function (data) {
const objects = [...data["shopping_results"]];
console.log("call back worked");
if (!objects) {
console.log("ERROR 404");
res.status(404).send();
}
res.status(200).send(objects);
};
// Show result as JSON
search.json(params, callback);
});
app.use(allowCrossDomain);
app.listen(3001, function () {
console.log("App is listening for queries");
})
and my fetch:
import updateOnSearchRequest from '../redux/actions/updateOnSearchRequest';
export default function searchRequestToApi(queryText, dispatch) {
fetch(`http://localhost:3001/${queryText}`, {
mode: 'no-cors',
})
.then(res => console.log(res.json()))
.then(data => data ? dispatch(updateOnSearchRequest(data)) : {});
}
I receive error at console.log(res.json()) even though server works fine and doesnt give any errors
First of all, you need to remove mode: "no-cors", as mentioned in this answer, using it will give you an opaque response, which doesn't seem to return data in the body.
Second, move your app.use(allowCrossDomain); to the top so it's higher than app.get("/:id", function (req, res) {....
And lastly, you must remove console.log from .then(res => console.log(res.json())).
In summary, your server should be:
const SerpApi = require("google-search-results-nodejs");
const search = new SerpApi.GoogleSearch("myApiKey");
const express = require("express");
const app = express();
var allowCrossDomain = function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
res.header("Access-Control-Allow-Headers", "Content-Type");
next();
};
app.use(allowCrossDomain);
app.get("/:id", function (req, res) {
console.log("Made request");
const searchText = req.params.id;
const params = {
q: searchText,
tbm: "shop",
};
const callback = function (data) {
const objects = [...data["shopping_results"]];
console.log("call back worked");
if (!objects) {
console.log("ERROR 404");
res.status(404).send();
}
res.status(200).send(objects);
};
// Show result as JSON
search.json(params, callback);
});
app.listen(3001, function () {
console.log("App is listening for queries");
});
And your fetch should be:
fetch(`http://localhost:3001/${queryText}`)
.then(res => res.json())
.then(data => data ? dispatch(updateOnSearchRequest(data)) : {});

JWT token invalid, but why

I'm doing one of my first exercises on authorization, but I can't understand what I'm doing wrong with this one. I'm trying to validate the JWT token, but it gives me back that it's invalid
I get the token with httpie:
http POST :4000/auth/login email=test#test.com password=test
And then I try validating with httpie:
http GET :4000/images authorization:"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImlhdCI6MTY0ODgyMDI3MCwiZXhwIjoxNjQ4ODI3NDcwfQ.AhArOvQTaJ7ohbPiyGiGTK5pFMWqjbZ5Kj9q2hXEhXU"
Which gives me: Invalid JWT token
This is my router/images.js
const { Router } = require("express");
const Image = require("../models").image;
const router = new Router();
const toData = require("../auth/jwt");
router.get("/images", async (req, res) => {
const auth =
req.headers.authorization && req.headers.authorization.split(" ");
if (auth && auth[0] === "Bearer" && auth[1]) {
try {
const data = toData(auth[1]);
const allImages = await Image.findAll();
res.send(allImages);
} catch (error) {
res.status(400).send("Invalid JWT token");
}
} else {
res.status(401).send({ message: "Please supply valid credentials" });
}
});
This is the router/auth.js
const { Router } = require("express");
const { toJWT, toData } = require("../auth/jwt");
const router = new Router();
router.post("/auth/login", async (req, res, next) => {
try {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).send("Email and password required");
} else {
res.send({ jwt: toJWT({ userId: 1 }) });
}
} catch (error) {
console.log(error.message);
next(error);
}
});
module.exports = router;
This is the auth/jwt.js
const jwt = require("jsonwebtoken");
const secret =
process.env.JWT_SECRET || "e9rp^&^*&#9sejg)DSUA)jpfds8394jdsfn,m";
const toJWT = (data) => {
return jwt.sign(data, secret, { expiresIn: "2h" });
};
const toData = (token) => {
return jwt.verify(token, secret);
};
module.exports = { toJWT, toData };
Hope somebody can help :)
Inside your router/images.js file, it looks like you are not requiring the toData method correctly. You are requiring the module with two exported functions, so if you use destructuruing, you would have to access your toData method like you did inside of auth.js.
Change line 4 of router/images.js to:
const { toData } = require("../auth/jwt");
When you require the auth/jwt file with a single const that is not destructured, you would access the exported methods of that file with dot notation:
const jwt = require("../auth/jwt");
jwt.toData(auth[0]);

Sinon - Spy on function defined within a function

I have a module that exports some express middleware that looks like this:
// my_middleware.js
module.exports = (someMiddleware) => {
function loadExternalData (val) { ... }
moreMiddleware.use(async function (req, res, next) {
const externalData = loadExternalData(req.headers['some-info'])
someMiddleware(externalData, req, res, next)
})
return myMiddleware
}
I'm trying to test the return value of loadExternalData and I'm not sure how to do it. I've tried this
it ('returns the expected response', function() {
const myMiddleware = require('my_middleware.js')
const someMiddleware = require('some_middleware.js')
const loadExternalData = sinon.spy(myMiddleware, 'loadExternalData')
myMiddleware(someMiddleware)
loadExternalData.should.have.returned('some data')
})
Which gives me the error TypeError: Attempted to wrap undefined property loadRegionInfos as function
What is the correct way to test this?

Route not executing after middleware

So I'm creating an authentication route but failing after executing the middleware.
verifyToken.js
module.exports = function (req, res, next) {
const token = req.get('auth-token')
if (!token) return res.status(401).send('Access Denied!')
try {
const verified = jwt.verify(token, process.env.TOKEN_SECRET)
req.user = verified
console.log(req.user) // successfully logging
next()
} catch (err) {
res.setHeader('Content-Type', 'application/json');
res.status(403).send('Invalid Token')
}
}
user.controller.js
exports.currentUser = verifyToken, async (req, res) => { // after verify token throwing an error 404
console.log('HIT') // not logging
// return res.send(req.user)
}
user.route.js
const { currentUser } = require('../controllers/users');
router
.route('/currentuser')
.post(currentUser)
I tried your code and I couldn't log 'HIT' as well. I suggest the following, split the exports # exports.currentUser into
var verifyToken = require('./verifyToken.js')
var response = async (req, res) => {
console.log('HIT') // not logging
// return res.send(req.user)
}
module.exports.currentUser = {verifyToken, response}
Then re-write route.js like this to get it to work.
const { currentUser } = require('./controller.js');
router.get('/currentUser', currentUser.verifyToken, currentUser.response)
To utilize next(), I had to use router.get('/get', middleware, callback). I changed the codes so that I could test it. You will need to edit the codes according to your context!

Categories

Resources