req.user is undefined when accessing other routes after passport authentication - node.js

I'm using the custom error handling of passportjs. When I finished authenticating and now redirect to other route, the req.user is now undefined on that route. Are there any configurations I need to do?
(req: any, res, next) => {
passport.authenticate('local-register', (err, user, info) => {
if (err) {
return next('Error Auth');
}
if (info) {
return next('Error Auth');
}
if (!user) {
return next('Error Auth');
}
req.logIn(user, (error: Error) => {
if (error) {
return next('Error Auth');
}
return next();
});
})(req, res, next);
app.get('/home', async (req, res, next) => {
console.log(req.user.id) // logs undefined
})
session.js file includes
const sessions = session({
cookie: {
maxAge: 86400000,
httpOnly: true,
secure: process.env.NODE_ENV === 'production' ? true : 'auto',
sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax',
},
name: 'sessionID',
genid: () => {
return nanoid(36);
},
resave: false,
secret: process.env.SESSION_SECRET ?? '',
saveUninitialized: false,
store: new Reddistore({ client: redisClient }),
});
my index.js file includes
app.use(sessions);
app.use(passport.initialize());
app.use(passport.session());

in your index.js file
const passport = require('passport');
const { passportStrategy } = require('./config/passportStrategy');
passportStrategy(passport);
in config/passportStrategy.js file
const {
Strategy, ExtractJwt
} = require('passport-jwt');
const User = require('../model/user');
const passportStrategy = (passport) => {
const options = {};
options.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
options.secretOrKey = "YOUR_SECRET";
passport.use('local-register',
new Strategy(options, async (payload, done) => {
try {
const result = await User.findOne({ _id: payload.id });
if (result) {
return done(null, result.toJSON());
}
return done('No User Found', {});
} catch (error) {
return done(error,{});
}
})
);
};
module.exports = { passportStrategy };
// your middleware should like this
(req: any, res, next) => {
passport.authenticate('local-register', (err, user, info) => {
if (err) {
return next('Error Auth');
}
if (info) {
return next('Error Auth');
}
if (!user) {
return next('Error Auth');
}
req.user = user; // <=== assign user to req.user
req.logIn(user, (error: Error) => {
if (error) {
return next('Error Auth');
}
return next();
});
})(req, res, next);
app.get('/home', async (req, res, next) => {
console.log(req.user.id) // now you can access user
})

Related

Passport local-auth cookie from Express App is not getting set in Vue3 app with axios

I am creating authentication with passportjs local strategy. So I did how it' is supposed to be done. But I don't know if something I am missing here or not.
Problem: After submitting the data from Vue 3 App a cookie supposed to be set in the browser to make sure that the user is
authenticated. Here the problem is the cookie is not being saved in
the browser. I tried the same thing with React app and that worked
Github Link: https://github.com/abeertech01/vue-cookie-problem-resolve
Here we have all the code.
Backend (server.js):
mongoose
.connect("mongodb://localhost:27017/local-auth")
.then((res) => console.log(`MongoDB is connected`))
.catch((err) => console.log("error: ", err))
//Middleware
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
app.use(
cors({
origin: ["http://localhost:3000", "http://127.0.0.1:5173"],
credentials: true,
})
)
app.use(
session({
secret: "secretcode",
resave: true,
saveUninitialized: true,
})
)
app.use(cookieParser("secretcode"))
app.use(passport.initialize())
app.use(passport.session())
require("./passportConfig")(passport)
//Route
app.post("/login", (req, res, next) => {
passport.authenticate("local", (err, user, info) => {
if (err) throw err
if (!user) res.send("No User Exists")
else {
req.logIn(user, (err) => {
if (err) throw err
res.send("Successfully Authenticated")
console.log("50 req.user", req.user)
})
}
})(req, res, next)
})
I did the passport things in a separate file and that is here in passportConfig,js:
const User = require("./user")
const bcrypt = require("bcryptjs")
const localStorage = require("passport-local").Strategy
module.exports = function (passport) {
passport.use(
new localStorage((username, password, done) => {
User.findOne({ username: username }, (err, user) => {
if (err) throw err
if (!user) return done(null, false)
bcrypt.compare(password, user.password, (err, result) => {
if (err) throw err
if (result === true) {
return done(null, user)
} else {
return done(null, false)
}
})
})
})
)
passport.serializeUser((user, cb) => {
cb(null, user.id)
})
passport.deserializeUser((id, cb) => {
User.findOne({ _id: id }, (err, user) => {
const userInformation = {
username: user.username,
}
cb(err, userInformation)
})
})
}
Now in frontend I used axios and the following is the frontend is in the following:
const login = () => {
axios({
method: "POST",
data: {
username: "abeer",
password: "123",
},
withCredentials: true,
url: "http://localhost:4000/login",
}).then((res) => console.log(res))
}
This is in the <script setup></script> tag. In the template tag I ued the function like this: <button #click="login">Login</button>

req.user is undefined, using typescript

i am new to typescript and i am working on an Oauth2.0 project with passport, the req.user returns undefined and i dont know why, here is my code.
function checkLoggedIn(req: Request, res: Response, next: NextFunction): any {
console.log('current user is: ', req.user);
const isLoggedIn = true;
if (!isLoggedIn) {
return res.status(401).json({
error: 'you must log in',
});
}
next();
}
i always get undefined when logging the user
current user is: undefined
anyone knows what is the course of this?
the whole code
async function verifyCallback(accessToken: any, refreshToken: any, profile: any, done: any) {
const newUser = {
googleId: profile.id,
displayName: profile.displayName,
email: profile.emails[0].value,
Image: profile.photos[0].value,
};
try {
let user = await Oauth.findOne({ googleId: profile.id });
if (user) {
done(null, profile);
} else {
user = await Oauth.create(newUser);
done(null, profile);
}
} catch (err) {
console.log(err);
}
}
passport.use(new Strategy(AUTH_OPTIONS, verifyCallback));
// save the session to the cookie
passport.serializeUser((user: any, done) => {
done(null, user.id)
});
// load the session from the cookie
passport.deserializeUser((id: any, done) => {
done(null, id)
});
app.use(helmet());
app.use(cookieSession({
name: 'session',
maxAge: 24 * 60 * 60 * 1000,
keys: [ config.COOKIE_KEY_1, config.COOKIE_KEY_2 ],
}))
app.use(passport.initialize());
app.use(passport.session());
function checkLoggedIn(req: Request, res: Response, next: NextFunction): any {
console.log('current user is: ', req.user);
const isLoggedIn = true;
if (!isLoggedIn) {
return res.status(401).json({
error: 'you must log in',
});
}
next();
}
// Authentication route
router.get(
'/auth/google',
passport.authenticate('google', {
scope: ['profile', 'email', 'https://www.googleapis.com/auth/youtube.upload'],
}),
);
router.get(
'/auth/google/callback',
passport.authenticate('google', {
failureRedirect: '/failure',
successRedirect: '/user',
session: true,
}),
(req, res) => {
console.log('google called us back');
},
);
router.get('/user', checkLoggedIn, async (req, res) => {
try {
const user: any = await Oauth.findOne({ username: String });
res.status(200).json(user);
} catch (err) {
res.status(500).json(err);
}
});
router.get('/logout', (req, res) => {
res.redirect('/')
});
router.get('/failure', (req, res) => {
res.send('failed to log in');
});
**
Try this
**
You can change the value (req.user) to (req.body.user)
function checkLoggedIn(req: Request, res: Response, next: NextFunction): any {
console.log('current user is: ', req.body.user);
const isLoggedIn = true;
if (!isLoggedIn) {
return res.status(401).json({
error: 'you must log in',
});
}
next();
}

error using express-jwt: jwt is not a function

I'm using express-jwt in my project but I'm getting this error, I couldn't find the solution
import jwt from "express-jwt";
const getTokenFromHeaders = (req) => {
const { headers: { authorization } } = req
if (authorization && authorization.spilt(' ')[0] === 'Token') {
return authorization.split(' ')[1]
}
return null
}
const auth = {
required: jwt({
secret: " /\-l/\Y",
userProperty: 'payload',
getToken: getTokenFromHeaders
}),
optional: jwt({
secret: "/\-l/\Y",
userProperty: 'payload',
getToken: getTokenFromHeaders,
credentialsRequired: false,
})
}
export default auth
this use
router.post("/login", auth.optinal, (req, res, next) => {
const { body: { user } } = req
if (!user.email && !user.password) {
return res.status(402).json({
errors: "Eposta veya şifre yanlış ! ",
});
return passport.authenticate('local', { session: false }, (err, passportUser, info)
=> {
if (err) {
return next(err)
}
if (passportUser) {
const user = passportUser
user.token = passportUser.genareteJWT();
return res.json({ user: user.toAuthJSON() })
}
return res.status(400).info;
})(req, res, next)
}
})
and error message:
required: jwt({
^
TypeError: jwt is not a function
at file:///C:/Users/atala/Desktop/atalayapp-main/backend/middleware/auth/auth.js:12:15
at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:385:24)
at async loadESM (node:internal/process/esm_loader:88:5)
at async handleMainPromise (node:internal/modules/run_main:61:12)

req.isAuthenticated() is returning true even after wrong password is entered

I am using passport local strategy to authenticate the users, here is my login code:
app.post("/login",function(req,res){
const user = new model({
username:req.body.username,
password:req.body.password,
});
req.login(user, function(err) {
if (err) {
res.render("login",{error: err});
} else {
passport.authenticate("local")(req, res, function() {
res.redirect("/dashboard");
});
}
});
});
Now if I enter an incorrect password then an unauthorized message comes and then if I go to my dashboard route then req.isAuthenticated() is true,
here is my dashboard code:
app.get("/dashboard",function(req,res){
if(req.isAuthenticated()){
//mywork
}
How to solve this problem and how/where to handle that unauthorized message?
passport.use(model.createStrategy());
passport.serializeUser(model.serializeUser());
passport.deserializeUser(model.deserializeUser());
and
app.use(session({
secret: "secret",
resave: false,
saveUninitialized: false,
}));
You're using req.login. Do you know what it does? Here is how you handle you'r issues, first you create a strategy ( obviously you have a user model ).
const User = require('../models/User');
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
/**
* Sign in using Email and Password.
*/
passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
User.findOne({ email: email.toLowerCase() }, (err, user) => {
if (err) { return done(err); }
if (!user) {
return done(null, false, { msg: `Email ${email} not found.` });
}
if (!user.password) {
return done(null, false, { msg: 'Your account was registered using a sign-in provider. To enable password login, sign in using a provider, and then set a password under your user profile.' });
}
user.comparePassword(password, (err, isMatch) => {
if (err) { return done(err); }
if (isMatch) {
return done(null, user);
}
return done(null, false, { msg: 'Invalid email or password.' });
});
});
}));
Then in your controller you can create a login method:
/**
* POST /login
* Sign in using email and password.
*/
exports.postLogin = (req, res, next) => {
const validationErrors = [];
if (!validator.isEmail(req.body.email)) validationErrors.push({ msg: 'Please enter a valid email address.' });
if (validator.isEmpty(req.body.password)) validationErrors.push({ msg: 'Password cannot be blank.' });
if (validationErrors.length) {
req.flash('errors', validationErrors);
return res.redirect('/login');
}
req.body.email = validator.normalizeEmail(req.body.email, { gmail_remove_dots: false });
passport.authenticate('local', (err, user, info) => {
if (err) { return next(err); }
if (!user) {
req.flash('errors', info);
return res.redirect('/login');
}
req.logIn(user, (err) => {
if (err) { return next(err); }
req.flash('success', { msg: 'Success! You are logged in.' });
res.redirect(req.session.returnTo || '/');
});
})(req, res, next);
};
To make sure you'r routes are authenticated:
app.get('/', homeController.index);
app.get('/login', userController.getLogin);
app.post('/login', userController.postLogin);
app.get('/logout', userController.logout);
app.get('/forgot', userController.getForgot);
app.post('/forgot', userController.postForgot);
app.get('/reset/:token', userController.getReset);
app.post('/reset/:token', userController.postReset);
app.get('/signup', userController.getSignup);
app.post('/signup', userController.postSignup);
app.get('/account/verify', passportConfig.isAuthenticated, userController.getVerifyEmail);
app.get('/account/verify/:token', passportConfig.isAuthenticated, userController.getVerifyEmailToken);
app.get('/account', passportConfig.isAuthenticated, userController.getAccount);
And your app settings for passport strategy session:
app.use(session({
resave: true,
saveUninitialized: true,
secret: process.env.SESSION_SECRET,
cookie: { maxAge: 1209600000 }, // two weeks in milliseconds
store: new MongoStore({
url: process.env.MONGODB_URI,
autoReconnect: true,
})
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use((req, res, next) => {
if (req.path === '/api/upload') {
// Multer multipart/form-data handling needs to occur before the Lusca CSRF check.
next();
} else {
lusca.csrf()(req, res, next);
}
});
app.use(lusca.xframe('SAMEORIGIN'));
app.use(lusca.xssProtection(true));
app.disable('x-powered-by');
app.use((req, res, next) => {
res.locals.user = req.user;
next();
});
app.use((req, res, next) => {
// After successful login, redirect back to the intended page
if (!req.user
&& req.path !== '/login'
&& req.path !== '/signup'
&& !req.path.match(/^\/auth/)
&& !req.path.match(/\./)) {
req.session.returnTo = req.originalUrl;
} else if (req.user
&& (req.path === '/account' || req.path.match(/^\/api/))) {
req.session.returnTo = req.originalUrl;
}
next();
});

Can't set headers after they are sent. using JWT

I'm trying to create an authentication with JWT, when I created my method it's a function called verifyJWT () it starts firing this error ...
NOTE: Before constructing this function and using it in the route, I can send it calmly, the problem is when I do res.status (200) .send ({auth: true, token: jwtToken}); and then res.redirect ('/ home/ v1'); But really I do not know why this problem ..
What is the correct mode of user authentication and on subsequent routes?
LOGIN ROUTER:
const { body } = require('express-validator/check');
module.exports = (app) => {
app.route('/')
.get((req, res) => { app.controllers.login.controller.redirectRouter(app, req, res) });
app.route('/login')
.get((req, res) => { app.controllers.login.controller.login(app, req, res); })
.post([
body('username').isString().isLength({ min: 1 }).not().isEmpty(),
body('password').isString().isLength({ min: 1 }).not().isEmpty()
], (req, res) => { app.controllers.login.controller.checkLoginForm(app, req, res); });
}
LOGIN CONTROLLER ROUTER
const { validationResult } = require('express-validator/check');
const jwt = require('jsonwebtoken');
module.exports.redirectRouter = (app, req, res) => res.redirect('/login');
module.exports.login = (app, req, res) => {
const renderConfig = new app.models.services.utilities.Render("LOGIN", true);
renderConfig.httpJSPResponseStatusCode = 200;
res.render('login/view', renderConfig.config);
}
module.exports.checkLoginForm = (app, req, res) => {
/** #description: RECEBE O RESULTADO DA VALIÇÃO DO FORMULÁRIO PELO {EXPRESS-VALIDATOR} */
const errors = validationResult(req);
/** #description: VERIFICA SE HOUVE ERRO NA VALIDAÇÃO DO FORMULÁRIO COM O {EXPRESS-VALIDATOR} */
if (!errors.isEmpty()) {
/** #description: CASO ALGUM DADO ESTEJA INCONSISTENTE RETORNA {ERROR: 401} DE {NÃO AUTORIZADO} */
res.status(401).send("401 Não autorizado");
} else {
/** #description: CASO OS DADOS FOREM VÁLIDOS, ADICIONA OS VALORES DO BODY NAS VARIÁVEIS */
const username = req.body.username,
password = req.body.password;
/** FUNÇÕES TEMPORÁRIAS */
if(username === "1" && password === "1"){
const userId = 10;
const jwtToken = jwt.sign({ userId }, process.env.SECRET, {
expiresIn: 300 // EXPIRA EM 5MIN
});
//res.status(200).send({ auth: true, token: jwtToken });
res.redirect('/home/v1');
} else {
res.status(401).send("401 Não autorizado");
}
}
}
HOME ROUTER
const jwtClass = require('../../models/services/JWT/controller.js');
module.exports = (app) => {
app.route('/home/v1/')
.get(jwtClass.verifyJWT, (req, res) => {
console.log("é get")
//app.controllers.home.controller.home(app, req, res);
}).post(jwtClass.verifyJWT, (req, res) => {
console.log("é post")
//app.controllers.home.controller.home(app, req, res);
});
}
** HOME CONTROLLER ROUTER **
module.exports.home = (app, req, res) => {
res.render('home/view');
}
JWT FUNCTION METHOD
const jwt = require('jsonwebtoken');
module.exports.verifyJWT = (req, res, next) => {
const jwtToken = req.headers['x-access-token'];
if (!jwtToken) {
return res.status(401).send({ auth: false, message: 'No token provided.' });
} else {
jwt.verify(jwtToken, process.env.SECRET, (error, decoded) => {
if (error) {
return res.status(500).send({ auth: false, message: 'Failed to authenticate token.' });
} else {
console.log("ae")
req.userId = decoded.id;
next();
}
});
}
}
//res.status(200).send({ auth: true, token: jwtToken });
res.redirect('/home/v1');
You can't redirect after sending Response. Refer the way Request and Response work in REST api. What you can do here is Redirect first and Have the Auth Token sent after Redirection (in the Redirection Route). You need to Write login after Redirection.
Update :
Try adding the line res.status(200).send({ auth: true, token: jwtToken });
inside HOME ROUTER
Also please import Proper Modules to HOME ROUTER.
const jwtClass = require('../../models/services/JWT/controller.js');
module.exports = (app) => {
app.route('/home/v1/')
.get(jwtClass.verifyJWT, (req, res) => {
console.log("é get")
//ADD HERE
res.status(200).send({ auth: true, token: jwtToken });
//app.controllers.home.controller.home(app, req, res);
}).post(jwtClass.verifyJWT, (req, res) => {
console.log("é post")
//ADD HERE
res.status(200).send({ auth: true, token: jwtToken });
//app.controllers.home.controller.home(app, req, res);
});
}
** HOME CONTROLLER ROUTER **
module.exports.home = (app, req, res) => {
res.render('home/view');
}

Resources