Reputation: 10665
I have an app using Express 4 with Passport 0.3.2. I have set up a passport-local
strategy, which is getting the correct user information when the /session
endpoint is sent a username and password.
However the user information is never saved correctly. As such req.user
is always undefined in all listeners and req.isAuthenticated()
always returns false.
I have seen other posts which often find issues with the ordering of the middleware setup however I have ordered them in the correct way and so I am not sure where to go from here.
Here is my POST
listener for /session
:
app.post("/session",
passport.authenticate('local'),
(req: any, res: any) => {
// if we reach this point, we authenticated correctly
res.sendStatus(201);
}
);
Here is my LocalStrategy
setup:
passport.use(new LocalStrategy(
(username, password, done) => {
let users = userRepository.getAll();
let usernameFilter = users.filter(u => u.getUsername() === username);
if (!usernameFilter || usernameFilter.length !== 1) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!password || password !== "correct") {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, usernameFilter[0]);
}
));
Here is my app setup:
let app = express();
app.use(cookieParser());
app.use(bodyParser.json());
app.use(expressSession({
secret: 'my secret key',
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
I am using the following dependency versions:
"body-parser": "^1.15.1",
"cookie-parser": "^1.4.3",
"express": "^4.13.4",
"express-session": "^1.13.0",
"passport": "^0.3.2",
"passport-local": "^1.0.0"
I have added a callback to my POST /session
, however an error is thrown. This is my callback:
app.post("/session",
passport.authenticate('local', {
session: false
}),
(req: express.Request, res: express.Response) => {
req.logIn(req.user, (err: any) => {
if (err)
throw err;
});
// if we reach this point, we authenticated correctly
res.sendStatus(201);
}
);
I get the following error thrown:
Error: Failed to serialize user into session
Upvotes: 6
Views: 8425
Reputation: 505
Cookie-parser and body-parser are not necessary for this. Just express-session
and passport
.
It seems to me like your cookies are not being sent or received because of your express-session configuration (or lack thereof)
In order to consume cross-site cookies, the sameSite
property needs to be set to none
. However, if the sameSite
property is set to none
, the secure
property is required to be set to true
. Which will make it so the cookie is only sent through HTTPS. This doesn't work when developing on http://localhost
.
To get around this, while in development sameSite
can be set to "lax" and secure can be set to "auto"
.
const inProd = process.env.NODE_ENV === "production";
app.use(
session({
secret: process.env.COOKIE_SECRET,
resave: true, // resave cookies even if nothing changed
saveUninitialized: false,
cookie: {
sameSite: `${inProd ? "none" : "lax"}`, // cross site // set lax while working with http:localhost, but none when in prod
secure: `${inProd ? "true" : "auto"}`, // only https // auto when in development, true when in prod
maxAge: 1000 * 60 * 60 * 24 * 14, // expiration time
},
})
);
Upvotes: 2
Reputation: 133
After looking at @JamesMonger's question and @pulse0ne's answer, I figured out how to fix my problem. My session was not getting created as well in react with passport and cookie-session. I am sharing the problem code and the solution here, so that someone can benefit from it. Old code that did not work
server.get('/auth/google/callback', passport.authenticate('google'),
(req, res) => {
res.redirect('/api/current_user');
});
After adding session: true, the session got created and I was able to retrieve it from the request.
server.get('/auth/google/callback', passport.authenticate('google', {session: true}),
(req, res) => {
res.redirect('/api/current_user');
});
Versions:
"body-parser": "^1.19.0",
"cookie-session": "^1.3.3",
"express": "^4.16.4",
"passport": "^0.4.0",
Upvotes: 1
Reputation: 4747
I found this question from a Google search when I had a related problem.
What I realized was that express-session
doesn’t persist sessions e.g. between server restarts. Read here for more info.
So I swapped express-session
for cookie-session
instead:
app.use(cookieSession({
name: 'MyAppName',
keys: ['very secret key'],
maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
}));
And then PassportJS was persisting my sessions, no further change needed!
Upvotes: 7
Reputation: 1102
From the passport docs:
Note that when using a custom callback, it becomes the application's responsibility to establish a session (by calling req.login()) and send a response.
Ah, good, we're making progress. You'll have to configure passport to serialize and deserialize the user information. See this for information. It should be noted that you will replace User
with your own database access object.
Upvotes: 4