in the last few hours I setup a backend express server. It works just fine and now I tryed to implement an authorization with help of a tutorial.
The login works, but when I try to open /authrequired (so basically a future page which needs a logged in user to work) I get the error message: "TypeError: req.isAuthenticated is not a function"
Here is my index.js file:
const express = require('express');
const fs = require('fs');
const http = require('http');
const https = require('https');
const path = require('path');
const uuid = require('uuid').v4;
const session = require('express-session');
const FileStore = require('session-file-store')(session);
const bodyParser = require('body-parser');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const users = [
{id: '2f24vvg', email: 'test#test.com', password: 'password'}
]
// configure passport.js to use the local strategy
passport.use(new LocalStrategy(
{ usernameField: 'email' },
(email, password, done) => {
console.log('Inside local strategy callback')
// here is where you make a call to the database
// to find the user based on their username or email address
// for now, we'll just pretend we found that it was users[0]
const user = users[0]
if(email === user.email && password === user.password) {
console.log('Local strategy returned true')
return done(null, user)
}
}
));
// tell passport how to serialize the user
passport.serializeUser((user, done) => {
console.log('Inside serializeUser callback. User id is save to the session file store here')
done(null, user.id);
});
passport.deserializeUser((id, done) => {
console.log('Inside deserializeUser callback')
console.log(`The user id passport saved in the session file store is: ${id}`)
const user = users[0].id === id ? users[0] : false;
done(null, user);
});
const app = express();
app.enable('trust proxy')
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(session({
genid: (req) => {
console.log('Inside the session middleware')
console.log(req.sessionID)
return uuid() // use UUIDs for session IDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
app.use(passport.session());
app.post('/login', (req, res, next) => {
console.log('Inside POST /login callback')
passport.authenticate('local', (err, user, info) => {
console.log('Inside passport.authenticate() callback');
console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
console.log(`req.user: ${JSON.stringify(req.user)}`)
req.login(user, (err) => {
console.log('Inside req.login() callback')
console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
console.log(`req.user: ${JSON.stringify(req.user)}`)
return res.send('You were authenticated & logged in!\n');
})
})(req, res, next);
})
function isAuthenticated (req, res, next) {
if (req.session.user) next()
else next('route')
}
app.get('/authrequired', isAuthenticated, function (req, res) {
res.send('you hit the authentication endpoint\n')
})
app.use(express.static(path.resolve(__dirname, 'build')));
app.use(express.json());
// Redirect from http port to https
http.createServer(function (req, res) {
res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(80,433) + req.url });
console.log("http request, will go to >> ");
console.log("https://" + req.headers['host'].replace(80,433) + req.url );
res.end();
}).listen(80, () => console.info('Listening on port', 80))
//Start https server
https.createServer({
key: fs.readFileSync('./ssl/privkey.key'),
cert: fs.readFileSync('./ssl/cert.cer'),
keepAlive: true
}, app).listen(443, () => console.info('Listening on port', 443));
Anyone got a clue? I saw similar questions on stackoverflow, but nothing worked for me.
There is no such function isAuthenticated. That's why you get the error.
Try replace it with if(req.session.user) {
Or by the example in express-session
// middleware to test if authenticated
function isAuthenticated (req, res, next) {
if (req.session.user) next()
else next('route')
}
app.get('/', isAuthenticated, function (req, res) {
// this is only called when there is an authentication user due to isAuthenticated
res.send('hello, ' + escapeHtml(req.session.user) + '!' +
' Logout')
})
EDIT: You also need to use passport session middleware, by adding
app.use(passport.session());
Make sure it is coming after the session init.
Related
here is some problem that i have... i have been tried days to figure it out but nothing make it working.
i have Node.js Express session on backend and there are users, when i make login i set req.session.userId = "userid" and i have middleware that check if req.session.userId exist and then next() so on Localhost everything worked fine but when i hosted my website i can’t access the req.session.userId it's mean the Middleware don’t next()
Frondend hosted: Netlify
Backend hosted: Nodechef
Mysql hosted: Nodechef
i don’t know, maybe i missed something or that i have to made some
changes when hosting...
i hope you guys have solution for me 🙌🏻
index.js
const express = require('express');
const cookieParser = require("cookie-parser");
const session = require('express-session');
const cors = require('cors');
const app = express();
app.use(express.json());
app.use(cookieParser());
app.use(cors({
origin: '***********',
credentials: true
}));
app.all('/', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Credentials", true);
next();
});
app.use(session({
secret: "******",
name: "*****",
saveUninitialized: true,
resave: true,
cookie: {
domain: '*******',
secure: true,
maxAge: 1000 * 60 * 60 * 24 * 365,
}
}))
app.get('/', (req, res) => {
res.send({ msg: "seccess" })
})
app.use('/users', require('./routes/users'))
const PORT = 3000
app.listen(process.env.PORT || PORT, () => {
console.log(`Express server listening on port ${PORT} `);
});
users/login
const router = require('express').Router()
router.post('/login', (req, res) => {
const { userEmail, userPassword } = req.body
db.query(`SELECT * FROM users WHERE userEmail = ?`, userEmail,
(err, result) => {
if (err) {
return res.send({ err: err })
} else {
if (!userEmail || !userPassword)
req.session.userId = user.id
res.send({ msg: "Login Succes", req: req.session, user: user.id })
}
})
});
Middleware
module.exports.onlyLoggedUsers = (req, res, next) => {
if (req.session.userId) {
next()
} else {
res.status(200).send({err:"sensetive content for logged users only, plesae log in"})
}
}
I just added app.enable('trust proxy')
and it is work temporarily, in safari this not work and also on smartphone, if I got to setting in safari and turn of Prevent Cross-Site Tracking it is working so my question is how I can run the application without turn of Prevent Cross-Site Tracking.
I am using react and nodejs with passportjs. I called a post request to validate the username and password using local strategy. and on same page, I have a button that calls a get request to just console.log(req.user).
The issue is: on route /login - post, I am being able to console.log(req.user) while when I click on a button to make a get request to /getstatus, it gives me undefined.
If you check the /login post route, the res.send(req.user) also sends undefined, whereas the console.log(req.user) is showing the right information in the console.
I need help, do not know what I am doing wrong.
Below I have my code:
const express = require("express");
const bodyParser = require("body-parser");
require("dotenv").config();
const mongoose = require("mongoose");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const cookieParser = require("cookie-parser");
const expressSession = require("express-session");
const cors = require("cors");
const session = require("cookie-session");
const LocalStrategy = require("passport-local").Strategy;
//............................Initialization of middleware..........................
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(cors());
app.use(cookieParser());
app.use(passport.initialize());
app.use(passport.session());
//..............connect to a database...............................
const Users = new mongoose.Schema({
username: String,
password: String,
});
Users.plugin(passportLocalMongoose);
const MyModel = mongoose.model("MyModel", Users);
passport.use(MyModel.createStrategy());
// passport.use(new LocalStrategy(MyModel.authenticate()));
passport.serializeUser(MyModel.serializeUser());
passport.deserializeUser(MyModel.deserializeUser());
mongoose.connect(
process.env.DB_HOST,
{
useNewUrlParser: true,
useUnifiedTopology: true,
},
() => {
console.log("Database Connected");
}
);
// };
//......................Routes........................
app.post(
"/login",
cors(),
passport.authenticate("local", {
failureRedirect: "/failure",
}),
function (req, res, next) {
res.send(req.user);
console.log(req.user);
}
);
app.get("/failure", (req, res) => {
res.send({
name: "fff",
age: 23,
status: 500,
msg: "Invalid Username or Password",
color: "danger",
});
});
app.post("/reg", cors(), (req, res) => {
let username = req.body.username;
let password = req.body.password;
// connectdb();
MyModel.register({ username: username, active: false }, password, function (
err,
user
) {
if (err) {
console.log(err);
} else {
res.send("Success");
}
});
});
app.get("/getstatus", (req, res) => {
console.log(req.user);
});
//...........Start Server..........................
app.listen(5000, () => {
console.log("Server Started on Port 5000");
});
I got the solution, the issue is not with passportJS. it is with Axios.
This line of code is needed:
Axios.defaults.withCredentials = true;
For some reason req.user is undefined, and after 4+ hours of trying to figure out why, I'm asking here. I even copy-pasted the server/index.js file of a friend's server, changed the auth strategy so it worked for mine, and I get the same issue.
Everything else is working. It redirects to auth0, comes back to the correct place, either creates a new user in the DB or finds the user. In passport.serializeUser it has all the data I passed along. But when I hit the '/auth/me' endpoint, req.user is undefined.
server/index.js
require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors')
const session = require("express-session");
const passport = require('passport');
const Auth0Strategy = require('passport-auth0');
const massive = require('massive');
const axios = require('axios');
const process = require("process");
const moment = require('moment');
const app = express();
//app.use(express.static(__dirname + './../build'));
app.use(bodyParser.json());
app.use(cors());
app.use(session({
secret: process.env.SECRET,
cookie: { maxAge: 60000 },
resave: false,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
// Use the session middleware
massive(process.env.CONNECTION_STRING)
.then( (db) => {
console.log('Connected to Heroku')
app.set('db', db);
}).catch(err=>console.log(err))
passport.use(new Auth0Strategy({
domain: process.env.AUTH_DOMAIN,
clientID: process.env.AUTH_CLIENT_ID,
clientSecret: process.env.AUTH_CLIENT_SECRET,
callbackURL: process.env.AUTH_CALLBACK
}, (accessToken, refreshToken, extraParams, profile, done) => {
const db = app.get("db");
const userData = profile._json;
db.find_user([userData.identities[0].user_id]).then(user => {
if (user[0]) {
return done(null, user[0]);
} else {
db.create_user([
userData.given_name,
userData.family_name,
userData.email,
userData.identities[0].user_id
])
.then(user => {
return done(null, user);
});
}
});
}))
passport.serializeUser( (user, done) => {
//console.log('serializeuser', user)
done(null, user);
})
passport.deserializeUser( (id, done) => {
app.get("db").find_session_user([id])
.then(user => {
console.log(user);
done(null, user[0]);
});
})
app.get('/auth', passport.authenticate('auth0'));
app.get('/auth/callback', passport.authenticate('auth0', {
successRedirect: process.env.SUCCESS_REDIRECT
}))
app.get('/auth/me', (req, res) => {
console.log('auth/me endpoint hit')
console.log(req.user)
if(!req.user){
return res.status(401).send('No user logged in.');
}
return res.status(200).send(req.user);
})
app.listen(process.env.PORT, () => console.log(`Listening on port: ${process.env.PORT}`));
server/.env
CONNECTION_STRING=postgres:*****
SECRET=*******
AUTH_DOMAIN=****.auth0.com
AUTH_CLIENT_ID=***
AUTH_CLIENT_SECRET=***
AUTH_CALLBACK=http://localhost:8084/auth/callback
SUCCESS_REDIRECT=http://localhost:3000/
PORT=8084
Try moving the app.get('/auth', passport.authenticate('auth0')); line after the app.get('/auth/me', (req, res) => { block. app.get can do regex matches and goes with the first one that matches (http://expressjs.com/en/api.html#path-examples), and I think it's trying to run the /auth logic for the /auth/me path.
eI'm using:
framework: express
template engine :handlebars
authentification: passport / passport-local
So login process goes well, but in logout i have a problem:
//routes/users.js
//logout
router.get("/logout",(req,res)=>{
req.logout();
req.flash("success_msg","You are logged out");
console.log(req.user);
res.render("users/login");
});
//views/users/login.js
{{user}}
//app.js:
// Setting Global variables:
app.use(function(req,res,next){
res.locals.success_msg = req.flash("success_msg");
res.locals.error_msg = req.flash("error_msg");
res.locals.error = req.flash("error");
res.locals.user = req.user || null;
next();
});
So the probleme is that when i clic on logout, i'm redirected to login view but the user object still there(not null),and when I refresh the user is initialised to null,
So my problem why the user haven't been set to null before refirection ?
Full files codes :(app.js, routes/users.js, /config/passport.js)
* app.js
const express = require('express');
const methodOverride = require('method-override');
const mongoose = require('mongoose');
const exphbs = require('express-handlebars');
const bodyParser = require('body-parser');
const flash = require('connect-flash');
const session = require('express-session');
//const path = require("path");
const passport = require('passport');
const app=express();
// load routes :
const ideas = require("./routes/ideas");
const users = require("./routes/users");
//---------------Mongoose Connect-----------------------
//Map global promise = get rid of warning
mongoose.Promise = global.Promise;
//Connect to mongoose
mongoose.connect('mongodb://localhost/vidjot-db',{
useMongoClient: true
})
.then(function(){
console.log("MongoDB connected ...");
})
.catch(err => console.log(err));
//----------------Middlewares set in Use-----------------
// Static folder Set:
//app.use(express.static(path.join(__dirname,'public')));
app.use(express.static('public'));
// Session middleware :
app.use(session({
secret: 'mySecret',
resave: true,
saveUninitialized: true,
//cookie: { secure: true }
}));
// passport middleware :
app.use(passport.initialize());
app.use(passport.session());
// handlebars middleware :
app.engine('handlebars', exphbs({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
// body parser middleware :
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
//methodOverride middleware:
app.use(methodOverride('_method'));
//Connect flash middleware:
app.use(flash());
//----------------My Own Middlewares-----------------
// Setting Global variables:
app.use(function(req,res,next){
res.locals.success_msg = req.flash("success_msg");
res.locals.error_msg = req.flash("error_msg");
res.locals.error = req.flash("error");
console.log("res.locals.user");
res.locals.user = req.user || null;
next();
});
/* app.use(function(req,res,next){
console.log("3ale rou7i");
console.log(Date.now());
req.att_x="karim";
next();
}) */
app.use(function(req,res,next){
console.log("hani ne5dem");
next();
});
//-----------------Routes-----------------------------
// Index Route:
app.get("/",(req,res) => {
res.render('index');
//console.log("get callback");
});
// about Route:
app.get("/about",(req,res)=>{
res.render("about",{title:"about1"});
});
// Use routes :
app.use("/ideas",ideas);
app.use("/users",users);
//--------------------------------------------------
//call local-strategy:
require("./config/passport")(passport);
//--------------------------------------------------
const port=5000;
app.listen(port,()=>{
console.log(`server started on port ${port}`);
});
* routes/users.js:
const express = require("express");
const mongoose = require("mongoose");
const bcrypt = require('bcryptjs');
const passport = require("passport");
const router = express.Router();
//--------------------------------------------------
// Load User Model:
require('../models/User');
const User = mongoose.model('Users');
//--------------------------------------------------
//login form
router.get("/login",(req,res)=>{
res.render("users/login");
});
//handle login form:
router.post('/login',
passport.authenticate('local', {
successRedirect: '/ideas',
failureRedirect: '/users/login',
failureFlash:true,
})
);
//logout
router.get("/logout",(req,res)=>{
req.logout();
req.flash("success_msg","You are logged out");
console.log("routes users",req.user);
res.render("users/login");
});
//register form
router.get("/register",(req,res)=>{
res.render("users/register");
});
// handle register form
router.post("/register",(req,res)=>{
let errors=[];
if(req.body.password != req.body.password2)
errors.push({"text":"password do not match"});
if(req.body.password.length < 4)
errors.push({"text":"password must be at least 8 characters"});
if(errors.length > 0)
res.render("users/register",{
errors:errors,
name:req.body.name,
email:req.body.email,
});
else{
User.findOne({email:req.body.email})
.then(user=>{
if(user){
req.flash("error_msg","email already registred");
res.render("/users/login");
}else{
const newUser = new User({
name:req.body.name,
email:req.body.email,
password:req.body.password,
date:req.body.date,
});
bcrypt.hash(newUser.password, 10, function(err, hash) {
if (err) throw err;
newUser.password=hash;
newUser
.save()
.then(user=>{
req.flash("success_msg","You are registered, You can connect Now");
res.redirect("/users/login");
}).catch(err=>{
console.log(err);
return;
});
});
}
})
}
});
//--------------------------------------------------
module.exports = router;
* config/passport.js :
const mongoose = require('mongoose');
const bcrypt = require("bcryptjs");
const LocalStrategy = require("passport-local").Strategy;
const passport = require("passport");
//-------------------------------------------------------
// Load User Model:
require('../models/User');
const User = mongoose.model('Users');
//-------------------------------------------------------
module.exports=function(passport){
passport.use(
new LocalStrategy({usernameField:'email'},function(email, password, done){
User.findOne({'email':email},function(err, user) {
if (err)
return done(err);
if (!user)
return done(null, false,{message:"You are not registred"});
if (!bcrypt.compareSync(password,user.password) ){
return done(null, false,{message:"Missing email or password !"});
}
return done(null, user);
});
}));
passport.serializeUser(function(user, done) {
console.log("SERIALIZE");
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
console.log("DESERIALIZE");
User.findById(id, function(err, user) {
done(err, user);
});
});
}
You have middleware that set res.locals based on a logged in user for every request.
Your res.render() template uses that res.locals data when rendering the page.
When you call req.logout(), nobody clears the res.locals that were already set when the user was still logged in so res.locals.user is now inaccurate.
So, when res.render() gets called after the logout, res.locals are still set as if the user is logged in and thus the page renders that way.
A simple solution is to clear the locals when you logout so they don't wrongly indicate the user is still logged in:
//routes/users.js
//logout
router.get("/logout",(req,res)=>{
req.logout();
// clear user before rendering to indicate logged out
res.locals.user = null;
req.flash("success_msg","You are logged out");
console.log(req.user);
res.render("users/login");
});
I am trying to fix the following error:
/home/ubuntu/workspace/src/util/utils.js:2
if (req.isAuthenticated()) {
^
TypeError: Cannot read property 'isAuthenticated' of undefined
at Object.isLogged (/home/ubuntu/workspace/src/util/utils.js:2:11)
at Object.<anonymous> (/home/ubuntu/workspace/src/routes/index.js:6:23)
I am using passport the following in my app:
require('dotenv').config()
const express = require('express')
//...
const session = require('express-session')
const passport = require('passport')
// configure passport
require('./config/passport')(passport)
const auth = require('./routes/auth')
const index = require('./routes/index')
const app = express()
// ...
app.use(
session({
secret: 'super-mega-hyper-secret',
resave: false,
saveUninitialized: true,
})
)
app.use(passport.initialize())
app.use(passport.session())
app.use((req, res, next) => {
res.locals.currentUser = req.user
next()
})
// routes
app.use('/', auth)
app.use('/', index)
app.listen(port, host, () => {
console.log(`Listening on ${host}:${port}`)
})
module.exports = app
My passport.js file looks like the following:
const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy
const service = require('../service/auth')
module.exports = () => {
passport-serialize-deserialize
passport.serializeUser((user, done) => {
done(null, user.id)
})
passport.deserializeUser(async function(id, done) {
const user = await service.findById(id)
done(null, user)
})
passport.use('local', new LocalStrategy({
usernameField: 'username',
}, async(username, password, done) => {
const user = await service.signin(username, password)
done(null, user)
}))
}
When my / gets called I am using the isLogged() function to control if a login is required:
const express = require('express')
const router = express.Router()
const utils = require('../util/utils')
router.get('/', utils.isLogged(), (req, res) => {
res.render('dashboard')
})
module.exports = router
The definition of the function can be found in my utils.js file, where the error log above is pointing:
function isLogged(req, res, next) {
if (req.isAuthenticated()) {
next()
} else {
res.redirect('/')
}
}
module.exports = {
isLogged,
}
The full code flow can be found in the following repo: passport example
Any suggestions what I am doing wrong?`
I appreciate your replies!
When you run this code:
router.get('/', utils.isLogged(), (req, res) => {
res.render('dashboard')
});
What happens is that utils.isLogged() is being executed, the the result of this execution is registered as a middleware.
Since you try to execute it without any parameters passed, res is passed as undefined and you get your error.
Now, what you really want to do is pass the function itself, not it's execution, so when express will call it (during request processing), it will pass the parameters to it. So your code should look like this:
router.get('/', utils.isLogged, (req, res) => {
res.render('dashboard')
});