Node + Express + Passport: req.user Undefined
node.jsExpresspassport.jsnode.js Problem Overview
My question is similar to this one, but there was no insight into his solution.
I'm using Passport to auth using Instagram. After successful auth, users are directed to "/". At this point, the request has the user object (aka it's working). However, once I redirect, the req.user is undefined. :'(
The odd part is that passport.deserializeUser is being called with each request. It's successfully getting the user object, but somewhere along the middleware road, req.user is not being set (or being unset).
// on successful auth, goto "/"
app.get('/', function(req, res) {
// if the request has the user object, go to the user page
if (req.user) {
res.redirect("/user/" + req.user._id);
}
res.render("index");
}
app.get('/user/:uid', function(req, res) {
console.log(req.user) // undefined
}
node.js Solutions
Solution 1 - node.js
My issue was not specifying to send cookies when using fetch on the client-side. It worked after including the credentials: 'include' field in the request.
fetch('/api/foo', {credentials: 'include'})
Solution 2 - node.js
Have you set up session state for your app? If you haven't, you need something like this...
app.use(session({ secret: 'anything' }));
app.use(passport.initialize());
app.use(passport.session());
Solution 3 - node.js
I am super new to Node but it was a middleware issue for me. Added bodyParser and rearranged to fix.
Broken code:
app.use(express.cookieParser('secret'));
app.use(express.cookieSession());
app.use(express.session({ secret: 'anything' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
Working Code:
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'anything' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
Hope this helps
Solution 4 - node.js
Previously I have these code (did not work):
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser('abcdefg'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
secret: 'abcdefg',
resave: true,
saveUninitialized: false,
cookie: { secure: true } // this line
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(require('stylus').middleware(path.join(__dirname, 'public')));
Then I remove the cookie option from session initializer:
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser('abcdefg'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
secret: 'abcdefg',
resave: true,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(require('stylus').middleware(path.join(__dirname, 'public')));
and now it works.
Solution 5 - node.js
I encounter the same problem because of just copy & paste following code from express-session documentation, but not fully read the documentation.
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
In the documentation, it mentioned:
> However, it requires an https-enabled website, i.e., HTTPS is > necessary for secure cookies. If secure is set, and you access your > site over HTTP, the cookie will not be set.
so if you just have a HTTP connection, remove the secure option,and below code should work:
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
//cookie: { secure: true } remove this line for HTTP connection
}))
Solution 6 - node.js
I think everyone has several mistakes on server-side which can cause this problem.
To solve this error, please check these things:
Check 1 - Passport Serialization and Deserialization
The correct way to do it (Mongoose):
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((_id, done) => {
User.findById( _id, (err, user) => {
if(err){
done(null, false, {error:err});
} else {
done(null, user);
}
});
});
Check 2 - Sessions
Check your cookie-session package is configured properly and working. Check if you can actually see cookie on client-side. If you are using express-session please make sure you can see session-id in memory or cache(Redis).
Check 3 - SSL nginx
Make sure your reverse proxy supports cookies and request type. Don't forget to check cookie/session configuration [secure
flag]
When I face this error, I was using (user)
for callback function. Then I corrected it with (err, user)
. Now its all right. Cheers
Solution 7 - node.js
Yeah enable sessions like @Martin says. But if you are using Express 4.* version, middleware like sessions are not bundled so you need to install it individually.
- Add "express-session": "1.4.0" in your package.json
- npm install
- use it
;
var express = require('express');
var cookieParser = require('cookie-parser')
var session = require('express-session')
var app = express()
app.use(cookieParser()) // required before session.
app.use(session({secret: 'keyboard cat'}))
For more information check the express session documentation.
Solution 8 - node.js
I had this exact same problem using express 4 and after trying pretty much everything I could find online I finally managed to get it working by adding 'cookie-session'.
var cookieSession = require('cookie-session');
app.use(cookieSession({
keys: ['key1', 'key2']
}));
Solution 9 - node.js
In routes, try adding: {session: true}
app.get('/auto-login', passport.authenticate('cross', {session: true}))
Solution 10 - node.js
When you authenticate a user, the request value req.user
is filled. To know if the identify the user and fill that value, a cookie is used.
If like me, you configure the session with secure cookies, cookies will be available only over HTTPS
, which is not the standard configuration for, let's say, a local development server. To have cookies work over HTTP
, comment out cookie: { secure: true }
and req.user
value will be properly configured:
this.app.use(session({
resave: true,
saveUninitialized: true,
secret: process.env.SESSION_SECRET || "a secret",
// cookie: { secure: true },
}));
If, reasonably, you want cookies over HTTPS
only in production, you can do something like:
cookie: { secure: process.env.ENV === 'PRODUCTION' }
Solution 11 - node.js
While doing passport.authenticate
you can add session: true
to resolve your issue:
app.post("/login", passport.authenticate('local', {
'failureRedirect': '/login',
'session': true
}), (req, res)=>{ res.redirect("/"); });
Solution 12 - node.js
'req.user' was being set to the user for me only after passport.auth middleware. I came to this thread trying to find out how to access the username from other requests (without passport.auth middleware), if anyone else is stuck on that issue then try
req._passport.session.user;
Solution 13 - node.js
Mine was about cookies & cors. I solved by adding following code to my server:
allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000'); // your website
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
if ('OPTIONS' === req.method) {
res.send(200);
} else {
next();
}};
Solution 14 - node.js
Once you have your express session setup make sure you have passport serialize & deserialize, in the deserialize function that's when req.user gets generated. See explanation here from another stackoverflow question.
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
Solution 15 - node.js
When u use http request on client side, remember to attach credentials. In Angular2 you need to add option argument: { withCredentials: true }. After this you will have the same req.sessionID until you reset it again.
this._http.get("endpoint/something", { withCredentials: true })
Solution 16 - node.js
Mine was different from all these. I had been previously developing on localhost a Wordpress site and then switched to a separate Node/React project.
The cookie from the Wordpress site was still present and being sent since both projects ran on localhost. This was causing the issue.
I had to clear the cookies for localhost and then it worked.
Solution 17 - node.js
Server sends SetCookie header then the browser handle to store it, and then the cookie is sent with requests made to the same server inside a Cookie HTTP header.
I had to set withCredentials: true in my client. (axios.js)
const config = {
withCredentials: true,
headers: {
'Content-Type': 'application/json',
},
};
axios.put(url, { page: '123' }, config)
.then(res => console.log('axios', res))
.catch(err => console.log('axios', err));
Then CORS problems occur.
So I added this to my express server:
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
if ('OPTIONS' == req.method) {
res.send(200);
} else {
next();
}
});
Solution 18 - node.js
If your middleware stack is unclear, assuming you have session middleware somewhere, you can save the session before the redirect:
if (req.user) {
req.session.save(function (err) {
if (err) {
// ... panic!
}
res.redirect("/user/" + req.user._id);
});
return;
}
Solution 19 - node.js
Have you tried to insert in the cookieParser your secretKey?
var passport = require('passport');
var expressSession = require('express-session');
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser('mySecretKey'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(expressSession({
secret: 'mySecretKey',
resave: false,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
Solution 20 - node.js
Had exactly the same problem. For me, the solution was to use "client-sessions" instead of 'express-session". Probably bad sessions configuration?
Not working code:
var session = require('express-session');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(session({
secret: 'random string',
resave: true,
saveUninitialized: true,
cookie: { secure: true }
}));
Working code:
var session = require('client-sessions');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(session({
cookieName: 'session',
secret: 'random string',
duration: 30 * 60 * 1000,
activeDuration: 5 * 60 * 1000,
}));
Solution 21 - node.js
I had same issue, both with req.isAuthenticated() and req.user, here is how I resolved
-
req.isAuthenticated() resolved by replacing findOne() with find() in findById() method inside deserialize(), then I could save authenticated req, else it was returning nothing.
-
req.user resolved by adjusting order, first express-session should be stored then passport should be initialized then next session store in passport.session() and after that we can access req.user, after saving session in passport.session()
app.use(session(...));
app.use(passport.initialize());
app.use(passport.session());
// Now we can access req.user so after we will call req.user, if we write it above these, it will always return underfined
app.use(function(req, res, next){
res.locals.user = req.user || null
next();
})
See, if you are accessing req.user after passport.session()
, if not add your route below.
Solution 22 - node.js
My two cents: not working code:
server.use(
session({
secret: "secretsssss",
rolling: false,
resave: false,
saveUninitialized: false,
cookie: {
sameSite: true, //this line
maxAge: 60 * 60 * 1000
}
})
);
working code:
server.use(
session({
secret: "secretsssss",
rolling: false,
resave: false,
saveUninitialized: false,
cookie: {
sameSite: false, // i think this is default to false
maxAge: 60 * 60 * 1000
}
})
);
Solution 23 - node.js
Ran into this same problem, however mine was more related to a misunderstanding of the difference between passport.authorize
and passport.authenticate
in the start of the OAuth flow and OAuth callback routes.
passport.authorize
won't affect the req.user
variable, but since I just copy-pasta'd the sample code from the strategy's docs, I didn't realize the wrong method was being used. After changing to passport.authenticate
the user variable was available.
Hope this helps anyone who may be unknowingly doing the same thing.
Solution 24 - node.js
Change the order from this:
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));
to this:
app.use(bodyParser.urlencoded({ extended: true }));
app.set("view engine", "ejs");
Solution 25 - node.js
I was using cookie-parser along with express-session like this:
var express = require("express"); // 4.16.1
var cors = require("cors"); // 2.8.5
var cookieParser = require("cookie-parser"); // 1.4.4
var expressSession = require("express-session"); // 1.17.1
var app = express();
app.use(
cors({
origin: "http://localhost:3000",
credentials: true,
})
);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(
expressSession({
secret: "secret123",
resave: true,
saveUninitialized: true,
cookie: { maxAge: 60 * 60 * 24 * 1000 },
})
);
app.use(cookieParser("secret123")); // this line
Putting cookie-parser before express-session worked for me, like this:
var express = require("express"); // 4.16.1
var cors = require("cors"); // 2.8.5
var cookieParser = require("cookie-parser"); // 1.4.4
var expressSession = require("express-session"); // 1.17.1
var app = express();
app.use(
cors({
origin: "http://localhost:3000",
credentials: true,
})
);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser("secret123"));
app.use(
expressSession({
secret: "secret123",
resave: true,
saveUninitialized: true,
cookie: { maxAge: 60 * 60 * 24 * 1000 },
})
);
Solution 26 - node.js
I had a different issue, something with bcrpt-node and arrow functions.
Code that works:
userSchema.methods.generateHash = function (password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
userSchema.methods.isValidPassword = function (password) {
return bcrypt.compareSync(password, this.password);
};
Code that does not work:
userSchema.methods.generateHash = (password) => {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
userSchema.methods.isValidPassword = (password) => {
return bcrypt.compareSync(password, this.password);
};