Cannot destructure property '_id' of 'req.user' as it is undefined - node.js

Doesn't work the request (below) as needed, drops out into an error:
app.get('/protected', auth.isAuthenticated(User), function(req, res) {
res.send('Hoooora! Authentificated!');
});
The isAuthenticated function is called from the auth.js file:
auth.js:
const SECRET = 'secret-message';
const jwt = require('jsonwebtoken');
const { expressjwt: expressJwt } = require('express-jwt');
const compose = require('composable-middleware');
function sign(user) {
return jwt.sign({
_id: user._id,
}, SECRET, {
expiresIn: 60 * 60
});
}
function sendUnauthorized(req, res) {
console.log(req.headers.authorization);
console.log(req.user);
res.status(401).json ({ message: 'Unathorized' });
};
const validateJwt = expressJwt({
secret: SECRET,
algorithms: ['HS256'],
fail: sendUnauthorized,
getToken(req){
if(req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
} else if (req.query && req.query.access_token) {
return req.query.access_token;
}
return null;
}
});
function isAuthenticated(User) {
console.log('isAuthenticated is called');
return compose()
.use(validateJwt)
.use((req, res, next) => {
// Attach user to request
const { _id } = req.user;
console.log(_id + req.user);
User.findById(_id, function(err, user) {
if (err) return next(err);
if (!user) return sendUnauthorized(req, res);
req.user = user;
console.log('Successfuly verified user by token: ');
next();
});
});
};
module.exports = {
sign,
sendUnauthorized,
isAuthenticated,
};
I get an error when the isAuthenticated function runs. And I don't figure out how to fix it:
"error":{"message":"Cannot destructure property '_id' of 'req.user' as it is undefined."
There is a suspicion that the body-parser or express is not working. Although I did yarn add body-parser and yarn add express. In the index.js file code I also added the following:
const express = require('express');
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());

Related

route saying forbidden although i issued user jwt

Using thunderclient (similar to postman) i cant access this employee api which requires a jwt, even though i confirm i am already authorized. Here is my code:
authController:
const usersDB = {
users: require("../model/users.json"),
setUsers: function (data) {
this.users = data;
},
};
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
require("dotenv").config();
const fsPromises = require("fs").promises;
const path = require("path");
const handleLogin = async (req, res) => {
const { user, pwd } = req.body;
if (!user || !pwd)
return res
.status(400)
.json({ message: "Username and password are required." });
const foundUser = usersDB.users.find((person) => person.username === user);
console.log(foundUser);
if (!foundUser) return res.sendStatus(401);
const match = await bcrypt.compare(pwd, foundUser.password);
if (match) {
const accessToken = jwt.sign(
{ username: foundUser.username },
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: "60s" }
);
const refreshToken = jwt.sign(
{ username: foundUser.username },
// we need our secret from env file as well to make our jwt
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: "1d" }
);
const otherUsers = usersDB.users.filter(
(person) => person.username !== foundUser.username
);
const currentUser = { ...foundUser, refreshToken };
usersDB.setUsers([...otherUsers, currentUser]);
await fsPromises.writeFile(
path.join(__dirname, "..", "model", "users.json"),
JSON.stringify(usersDB.users)
);
res.cookie("jwt", refreshToken, {
httpOnly: true,
ameSite: "None",
secure: true,
maxAge: 24 * 60 * 60 * 1000,
});
res.json({ accessToken });
} else {
res.sendStatus(401);
}
};
module.exports = { handleLogin };
sever.js:
const express = require("express");
const app = express();
const path = require("path");
const cors = require("cors");
const corsOptions = require("./config/corsOptions");
const { logger } = require("./middleware/logEvents");
const errorHandler = require("./middleware/errorHandler");
const cookieParser = require("cookie-parser");
const verifyJWT = require("./middleware/verifyJWT");
const PORT = process.env.PORT || 3500;
app.use(logger);
app.use(cors(corsOptions));
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "./public")));
// routes
app.use("/", require("./routes/root"));
app.use("/register", require("./routes/register"));
app.use("/auth", require("./routes/auth"));
app.use("/refresh", require("./routes/refresh"));
app.use(verifyJWT);
app.use("/employees", require("./routes/api/employees"));
app.all("/*", (req, res) => {
res.status(404);
if (req.accepts("html")) {
res.sendFile(path.join(__dirname, "views", "404.html"));
} else if (req.accepts("json")) {
res.json({ error: "404 Not Found" });
} else {
res.type("txt").send("404 not found");
}
});
app.use(errorHandler);
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
verifyJWT middleware:
const jwt = require("jsonwebtoken");
require("dotenv").config();
const verifyJWT = (req, res, next) => {
const authHeader = req.headers["authorization"];
if (!authHeader) return res.sendStatus(401);
console.log(authHeader);
// bearer token, hence bearer space 1, 1 is the token
const token = authHeader.split("")[1];
// decoded info from the jwt
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, decoded) => {
// 403 is forbidden
if (err) return res.sendStatus(403);
req.user = decoded.username;
next();
});
};
module.exports = verifyJWT;
so if i for example
http://localhost:3500/auth (post) and login with a user and pwd, my res does log an access token, and if i try to use that inside
http://localhost:3500/employees (get) i get forbidden. not sure what i am missing here
i tried console.logging to see if i had foundUser, which i did, so not sure why i cant get into this route
You are splitting by empty string, it would divide every character, try spliting by space:
const token = authHeader.split(" ")[1];

I keep getting "Login sessions require session support" when I try to use tokens

So I am following a tutorial on how to use JSON tokens and I am getting an error, it was working fine using sessions but I can't figure out why I am having trouble, it is the exact code
this is my authenticate.js file:
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const User = require("./models/user");
const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
const jwt = require("jsonwebtoken"); // used to create, sign, and verify tokens
const config = require("./config.js");
exports.local = passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
exports.getToken = function (user) {
return jwt.sign(user, config.secretKey, { expiresIn: 3600 });
}; // config.secretKey is a string of random numbers
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secretKey;
exports.jwtPassport = passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
console.log("JWT payload:", jwt_payload);
User.findOne({ _id: jwt_payload._id }, (err, user) => {
if (err) {
return done(err, false);
} else if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
})
);
exports.verifyUser = passport.authenticate("jwt", { session: false });
This is my app.js file (the main file):
const createError = require("http-errors");
const express = require("express");
const path = require("path");
const logger = require("morgan");
const config = require("./config");
const indexRouter = require("./routes/index");
const usersRouter = require("./routes/users");
const mongoose = require("mongoose");
const passport = require("passport");
const url = config.mongoUrl;
const connect = mongoose.connect(url, {
useCreateIndex: true,
useFindAndModify: false,
useNewUrlParser: true,
useUnifiedTopology: true,
});
connect.then(
() => console.log("Connected correctly to server"),
(err) => console.log(err)
);
const app = express();
// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "jade");
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// app.use(cookieParser("12345-67890-09876-54321"));
app.use(passport.initialize());
app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use(express.static(path.join(__dirname, "public")));
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
// render the error page
res.status(err.status || 500);
res.render("error");
});
module.exports = app;
this is the routes/users.js file (I believe the problem is here because I can sign-up (create new users) but I can't login with the same users)
const express = require("express");
const User = require("../models/user");
const passport = require("passport");
const authenticate = require("../authenticate");
const router = express.Router();
/* GET users listing. */
router.get(
"/",
function (req, res, next) {
res.send('send users')
}
);
router.post("/signup", (req, res) => {
User.register(
new User({ username: req.body.username }),
req.body.password,
(err, user) => {
if (err) {
res.statusCode = 500;
res.setHeader("Content-Type", "application/json");
res.json({ err: err });
} else {
if (req.body.firstname) {
user.firstname = req.body.firstname;
}
if (req.body.lastname) {
user.lastname = req.body.lastname;
}
user.save((err) => {
if (err) {
res.statusCode = 500;
res.setHeader("Content-Type", "application/json");
res.json({ err: err });
return;
}
passport.authenticate("local")(req, res, () => {
res.statusCode = 200;
res.setHeader("Content-Type", "application/json");
res.json({
success: true,
status: "Registration Successful!",
});
});
});
}
}
);
});
// I tried to add a console.log inside of the .post() route but it never reach it
router.post(
"/login",
passport.authenticate("local"),
(req, res) => {
const token = authenticate.getToken({ _id: req.user._id });
res.statusCode = 200;
res.setHeader("Content-Type", "application/json");
res.json({
success: true,
token: token,
status: "You are successfully logged in!",
});
}
);
router.get("/logout", (req, res, next) => {
if (req.session) {
req.session.destroy();
res.clearCookie("session-id");
res.redirect("/");
} else {
const err = new Error("You are not logged in!");
err.status = 401;
return next(err);
}
});
module.exports = router;
Basically, every time that i go to localhost:3000/users/login and send a POST request with the username and password, it tells me that I need to use express-session but I am trying to use tokens instead of session
The problem is caused when passport.authenticate('local') is called in routes/users.js file. It is a middleware that automatically calls req.login function in case correct username and password is provided.
The req.login() in turn, implements sessions in order to serialise the user in the session.
You can solve the issue by adding another parameter to passport.authenticate() as passport.authenticate('local', {session: false}. This ensures sessions are not implemented in the 'local' strategy and subsequently login can be performed.
Thanks, it helped me. You have to remove app.use(passort.session) from app.js and do
router.post('/login', passport.authenticate('local', { session: false }), (req, res) => {
var token = authenticate.getToken({ _id: req.user._id });
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json({ success: true, token: token, status: 'You are successfully logged in!' });
});

How to send jwt token to protected route in node.js

I have created a login form that should redirect the user to a dashboard page in case he enters the right password and username. If the user tries to navigate to the dashboard url without being logged in the page should not display as it is a protected route. I am trying to send a jwt token when the user logs in, but that doesn't work I just get the Forbidden message when I log in so it seems that the token is not sent correctly, how can I send the jwt token and access the protected route once the user logs in successfully?
Here is my server.js:
const express = require('express');
const jwt = require('jsonwebtoken');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
let Post = require('./models/post.model.js');
const app = express();
const cors = require('cors');
require('dotenv').config();
app.use(cors());
app.use("/assets", express.static(__dirname + "/assets"));
app.use(bodyParser.urlencoded({ extended: true }));
const BASE_URL = process.env.BASE_URL;
const PORT = process.env.PORT || 1337;
mongoose.connect(BASE_URL, { useNewUrlParser: true, useUnifiedTopology: true })
const connection = mongoose.connection;
connection.once('open', function () {
console.log('Connection to MongoDB established succesfully!');
});
app.set('view-engine', 'ejs');
app.get('/', (req, res) => {
res.render('index.ejs');
});
app.post('/', (req, res) => {
let username = req.body.username;
let password = req.body.password;
const user = {
username: username,
password: password
}
jwt.sign({ user }, process.env.SECRET_KEY, (err, token) => {
res.json({
token
})
});
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
res.json('Invalid credentials');
} else {
res.setHeader('Authorization', 'Bearer '+ token);
res.redirect('/dashboard')
}
});
app.get('/dashboard', verifyToken, (req, res) => {
jwt.verify(req.token, process.env.SECRET_KEY, (err, authData) => {
if (err) {
res.sendStatus(403);
} else {
res.sendStatus(200);
}
});
res.render('dashboard.ejs');
});
app.get('/dashboard/createPost', verifyToken, (req, res) => {
res.render('post.ejs');
});
app.post('/dashboard/createPost', async (req, res) => {
let collection = connection.collection(process.env.POSTS_WITH_TAGS);
res.setHeader('Content-Type', 'application/json');
let post = new Post(req.body);
collection.insertOne(post)
.then(post => {
res.redirect('/dashboard')
})
.catch(err => {
res.status(400).send(err);
});
});
// TOKEN FORMAT
// Authorization: Bearer <access_token>
//Verifing the Token
function verifyToken(req, res, next) {
// Get auth header value
const bearerHeader = req.headers['authorization'];
// Check if bearer is undefined
if (typeof bearerHeader !== 'undefined') {
// Spliting the bearer
const bearer = bearerHeader.split(' ');
// Get token from array
const bearerToken = bearer[1];
// Set the token
req.token = bearerToken;
// Next middleware
next();
} else {
// Forbid the route
res.sendStatus(403);
}
}
app.listen(PORT);
see this example, i use middleware(checkAuthLogin), this code contains all thing for your question:
index.js:
const express = require('express');
const app = express();
require('./db/mongoose');
const userRouter = require('./routers/user');
app.use(express.json());
app.use(userRouter);
app.listen(3000, ()=> {
console.log('Server is up on port ', 3000)
});
db/mongoose.js:
const mongoose = require('mongoose');
mongoose.connect("mongodb://127.0.0.1:27017/db-test" {
useNewUrlParser : true,
useCreateIndex : true,
useFindAndModify : false,
useUnifiedTopology: true
});
routers/user.js:
const express = require('express');
const router = new express.Router();
const RootUser = require('../models/root-user');
const {checkRootLogin} = require('../middleware/checkAuthLogin');
router.post('/createrootuser', async (req, res) => {
const updates = Object.keys(req.body);
const allowedUpdatesArray = ['name', 'password'];
const isValidOperation = updates.every((update) => allowedUpdatesArray.includes(update));
if (!isValidOperation) {
return res.status(400).send({error: 'Invalid Request Body'})
}
const rootUser = new RootUser(req.body);
try {
await rootUser.save();
// sendWelcomeEmail(user.email, user.name)
const token = await rootUser.generateAuthToken();
//console.log(user)
res.status(201).send({rootUser, token});
} catch (e) {
res.status(400).send(e)
}
});
//use this middleware(checkRootLogin) for check root user can access this function
router.post('/rootconfig', checkRootLogin, async (req, res) => {
res.status(200).send({success: 'success add root config'})
});
module.exports = router;
model/root-user.js:
const mongoose = require('mongoose');
const validator = require('validator');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const userRootSchema = new mongoose.Schema({
name: {
type : String,
required: true,
unique : true,
trim : true,
lowercase : true,
},
password: {
type : String,
required: true,
unique : true,
trim : true,
lowercase : true,
minlength : 6,
validate (value) {
//if (validator.contains(value.toLowerCase(), 'password')){
if (value.toLowerCase().includes('password')){
throw new Error('Password can not contained "password"')
}
}
},
tokens : [{
token : {
type : String ,
required : true
}
}],
}, {
timestamps: true
});
userRootSchema.methods.generateAuthToken = async function(){
const root = this;
// generate token
try {
// const token = jwt.sign({ _id : user._id.toString()}, process.env.JWT_SECRET);
const token = jwt.sign({ _id : root._id.toString()}, "test");
// add token to user model
root.tokens = root.tokens.concat({ token });
await root.save();
return token
} catch (e){
throw new Error(e)
}
};
userRootSchema.pre('save', async function(next){
// this give ccess to individual user
const user = this;
if (user.isModified('password')){
user.password = await bcrypt.hash(user.password, 8)
}
next()
});
const UserRoot = mongoose.model('UserRoot', userRootSchema);
module.exports = UserRoot;
middleware/checkAuthLogin.js:
const jwt = require('jsonwebtoken');
const RootUser = require('../models/root-user');
const checkRootLogin = async (req, res, next) => {
try {
const token = req.header('Authorization').replace('Bearer ', '');
// const decoded = jwt.verify(token, process.env.JWT_SECRET);
const decoded = jwt.verify(token, "test");
const rootUser = await RootUser.findOne({_id: decoded._id, 'tokens.token': token});
if (!rootUser) {
throw new Error("User cannot find!!");
}
req.token = token;
req.rootUser = rootUser;
req.userID = rootUser._id;
next()
} catch (e) {
res.status(401).send({error: 'Authentication problem!!'})
}
};
module.exports = {checkRootLogin};
Your issue is that your token variable is only accessible inside of the callback to the jwt.sign call, so when you try to do this here res.setHeader('Authorization', 'Bearer '+ token);, it won't know what variable you're referring to, hence the undefined error. By the way, if you're going to use jwt.sign asynchronously, then the code that uses it needs to also be inside of the callback, otherwise synchronous code outside of the callback will likely execute first (and thus not be able to access any results of the asynchronous code) as the asynchronous callback executes in the background. The solution here is to either switch your usage to a synchronous usage or place your response code inside of the callback. Also, calling res.json will end the response so I'm not sure what exactly you're trying to accomplish with the multiple response calls
Synchronous version:
app.post('/', (req, res) => {
let username = req.body.username;
let password = req.body.password;
const user = {
username: username,
password: password
};
let token = undefined;
try {
token = jwt.sign({ user }, process.env.SECRET_KEY);
} catch (e) {
// handle error
}
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
res.json('Invalid credentials');
} else {
res.setHeader('Authorization', 'Bearer '+ token);
res.redirect('/dashboard');
}
});
Asynchronous version:
app.post('/', (req, res) => {
let username = req.body.username;
let password = req.body.password;
const user = {
username: username,
password: password
}
jwt.sign({ user }, process.env.SECRET_KEY, (err, token) => {
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
res.json('Invalid credentials');
} else {
res.setHeader('Authorization', 'Bearer '+ token);
res.redirect('/dashboard')
}
});
});
In these examples, I took out res.json({ token }) because you can't use res.json and then perform a redirect, but modify those parts however best fits your code. On another note, you probably don't want to include the password in your token because while JWTs (when using the default/standard algorithms which do not include encryption) are cryptographically guaranteed to be unmodifiable, they are still readable
I have one solution to send jwt token, but you will need to install one more package. If you think it worth maybe you can follow.
I use express only for backend api. But you can use the same logic applied here to your application.
The lib you will need to install is the express-jwt
It handles routes to block access to endpoint that need authentication.
server.js
require('dotenv').config()
const express = require('express');
const logger = require('morgan');
const cors = require('cors');
const jwt = require('jsonwebtoken');
const expressJwt = require('express-jwt');
const app = express();
cors({ credentials: true, origin: true });
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use('/secure', expressJwt({ secret: process.env.SECRET }));
app.use(require('./server/index'));
app.get('/secure/dashboard') => {
//now you can only access this route with authorization header
//prependending the '/secure/ to new routes should make them return 401 when accessed without authorization token
//accessing this route without returns 401.
//there is no need to validate because express-jwt is handling.
console.log(res.user)//should print current user and pass signed with token
res.render('dashboard.ejs');
});
app.post('/', (req, res) => {
let username = req.body.username;
let password = req.body.password;
//jwt.sign({ user }, process.env.SECRET_KEY, (err, token) => {
// res.json({
// token
// })
//});
//shouldn't sign json here, because there is no guarantee this is a valid
//username and password it can be an impostor
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
res.json('Invalid credentials');
} else {
const user = {
username: username,
password: password
};
const tk = {};
tk.token = 'Bearer ' + jwt.sign(user, process.env.SECRET_KEY, { expiresIn: 1800 });//expires in 1800 seconds
res.status(200).json(tk);
}
});
Now in your frontend put the authorization token sent by this route in cookies or store in client-side.
Do the next request with the header authorization for the secure dashboard route.
I think the problem in the sign in controller function
you must check first if the user have the correct password before attempting to send him a token
you should save the result of jwt sign function in a variable to send back to the user in case he has the right credintials.
It make no sense to send the password again to the user , only the username is needed
you can try this :
app.post('/', (req, res) => {
const {username , password} = req.body;
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
return res.json('Invalid credentials');
}
const token = jwt.sign({username:username }, SECRET)
res.setHeader('Authorization', token);
res.redirect('/dashboard')
});

losing session on refresh NodeJs

I am following a tutorial on Udemy and creating a react app using node and express. I am losing my session and being sent back to the login page on refresh. The instructors app stays in session on refresh. Could bad routing be causing this issue? I'll provide auth.js file from my routing folder. I can add more if needed.
<<< SERVER.JS file >>>
const express = require('express');
const connectDB = require('./config/db');
const app = express();
// CONNECT To Database
connectDB();
// Init Middleware
app.use(express.json({extended: false}))
app.get('/', (req, res) => res.send('Well, hello there!'));
app.use('/api/posts', require('./routes/api/posts'));
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/profile', require('./routes/api/profile'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`server is listening on port ${PORT}`));
<<< middleware >>>
const jwt = require('jsonwebtoken');
const config = require('config');
module.exports = function(req, res, next) {
// Get token from header
const token = req.header('x-auth-token');
// Check if not token
if (!token) {
return res.status(401).json({ msg: 'No token, authorization denied' });
}
// Verify token
try {
const decoded = jwt.verify(token, config.get('jwtSecret'));
req.user = decoded.user;
next();
} catch (err) {
res.status(401).json({ msg: 'Token is not valid' });
}
};
just in case my here is my auth.js file from routing folder
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const auth = require('../../middleware/auth');
const jwt = require('jsonwebtoken');
const config = require('config');
const { check, validationResult } = require('express-validator');
const User = require('../../models/User');
// #route GET api/auth
// #desc Test route
// #access Public
router.get('/', auth, async (req, res) => {
try {
const user = await User.findById(req.user.id).select('-password');
res.json(user);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
// #route POST api/auth
// #desc Authenticate user & get token
// #access Public
router.post(
'/',
[
check('email', 'Please include a valid email').isEmail(),
check('password', 'Password is required').exists()
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { email, password } = req.body;
try {
let user = await User.findOne({ email });
if (!user) {
return res
.status(400)
.json({ errors: [{ msg: 'Invalid Credentials' }] });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res
.status(400)
.json({ errors: [{ msg: 'Invalid Credentials' }] });
}
const payload = {
user: {
id: user.id
}
};
jwt.sign(
payload,
config.get('jwtSecret'),
{ expiresIn: 360000 },
(err, token) => {
if (err) throw err;
res.json({ token });
}
);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
}
);
module.exports = router;

Exposing user object inside the req object

I am trying to get user object inside the req, so I can have it on all my routes. This is my setup:
app.js:
// Use the passport middleware
app.use(passport.initialize());
// load passport strategies
const localSignupStrategy = require('./server/passport/local-signup');
const localLoginStrategy = require('./server/passport/local-login');
passport.use('local-signup', localSignupStrategy);
passport.use('local-login', localLoginStrategy);
// View engine setup
app.set('views', path.join(__dirname, '/server/views'));
app.set('view engine', 'pug');
// Serve static assets normally
app.use(express.static(path.join(__dirname, '/dist')));
// Define routes
app.use('/auth', auth); //Auth controller
app.use('/api', api);
Route for Auth controller:
const express = require('express');
const router = express.Router();
const authController = require('../main/controllers/authController');
// POST /auth/signup
router.post('/signup', authController.postSignup);
// POST /auth/login
router.post('/login', authController.postLogin);
module.exports = router;
authController.postLogin
exports.postLogin = function(req, res, next) {
const validationResult = validateLoginForm(req.body);
if (!validationResult.success) {
return res.status(400).json({
success: false,
message: validationResult.message,
errors: validationResult.errors
});
}
return passport.authenticate('local-login', (err, token, userData) => {
if (err) {
if (err.name === 'IncorrectCredentialsError') {
return res.status(400).json({
success: false,
message: err.message
});
}
return res.status(400).json({
success: false,
message: 'Could not process the form.'
});
}
return res.json({
success: true,
message: 'Login success.',
token,
user: userData
});
})(req, res, next);
};
This is my normal controller route:
// GET /api/cms
router.get('/cms/', authCheck(), getCmsDataController.getCmsData);
module.exports = router;
authcheck.js
module.exports = function(roles) {
// Return middleware
return (req, res, next) => {
if (!req.headers.authorization) {
return res.status(401).end();
}
// Get the last part from a authorization header string like "bearer token-value"
const token = req.headers.authorization.split(' ')[1];
// Decode the token using a secret key-phrase
return jwt.verify(token, config.jwtSecret, (err, decoded) => {
// 401 not unauthorized
if (err) return res.status(401).end();
const userId = decoded.sub;
// Check if user exists
return User.findById(userId, (err2, user) => {
if (err2 || !user) return res.status(401).end();
req.currentLoggedUser = user;
console.log(user.role);
if (roles) {
if (roles.indexOf(user.role) > -1) return next();
else return res.status(401).end();
}
return next();
});
});
};
};
And the controller itself:
// GET /api/cms-data/
exports.getCmsData = function(req, res, next) {
return res.json({
message: 'Lets see does this thing work or not!!!'
});
};
Issue is when I reach the getCmsData controller, I would like to have a user object inside the req object. My user has some properties like role and gender, which I need access to. I have one hacky solution, but I think there is a way to do that.
Could you create a middleware function for this purpose:
function getRequestUser(req) {
// In reality you'd load from data store based on request.
return {id: 1, name: "Jim Smith"};
}
function addUserMiddleWare(req, res, next) {
req.user = getRequestUser(req);
next();
}
// Then add it to your route.
// GET /api/cms
router.get('/cms/', authCheck(), addUserMiddleWare, getCmsDataController.getCmsData);
module.exports = router;
// Or, apply to all paths on router
router.use(addUserMiddleWare);

Resources