I have a GraphQl server and a react frontend. I use passport and LocalStrategy to authenticate the user which works well, I can successfully login an existing user. I also want to use passport session to create a user session, so that I can access the logged in user later in my GraphQl resolvers for authentication. I expected passport to set the user in the session after successfully authenticating one. But after sending correct credentials from the client to the server, GraphQl queries do not have access to req.user
.
The GraphQL server code looks like this:
import express from 'express';
import passport from 'passport';
import {Strategy as LocalStrategy} from 'passport-local';
import session from 'express-session';
import cors from 'cors';
import bodyParser from 'body-parser';
import models from './models';
import typeDefs from './schema';
import resolvers from './resolvers';
import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
import { makeExecutableSchema } from 'graphql-tools';
export const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
const app = express();
app.use('*', cors({ origin: 'http://localhost:3000' }));
app.set('port', (process.env.PORT || 3001));
//--- Passport ----
app.use(session({
saveUninitialized: true,
resave: false,
secret: 'verysecretsecret'
}));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
passport.use(new LocalStrategy(
{
usernameField: 'email',
passwordField: 'password',
},
function(email, password, done) {
models.User.findOne({
where: {
email: email
}
}).then(function(user) {
if (user) {
if (user.validPassword(password)) {
return done(null, user);
} else {
return done(null, false);
}
}
return done(null, false);
});
}
));
//--- Routes ----
app.use('/graphiql', graphiqlExpress({
endpointURL: '/graphql'
}));
app.use(
'/graphql',
bodyParser.json(),
graphqlExpress( (req) => {
console.log('/graphql User: ' + req.user); // prints undefined after sending correct login credentials to /login
return ({
schema,
context: {
user: req.user,
},
});}),
);
app.use(bodyParser.urlencoded({ extended: true }) );
app.post('/login', passport.authenticate('local'), (req, res) => {
console.log('/login: User', req.user); // prints the logged in user's data
return res.sendStatus(200);
});
export default app;
And this is the login fetch request from the client:
onSubmit = () => {
var details = {
'email': this.state.email,
'password': this.state.password,
};
var formBody = [];
for (var property in details) {
var encodedKey = encodeURIComponent(property);
var encodedValue = encodeURIComponent(details[property]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
fetch('http://localhost:3001/login', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
credentials: 'include',
body: formBody
}).then(function(response) {
console.log(response);
}).catch(function(err) {
// Error
});
};
Do I have to change something on the client side for the server to receive the session cookie? Or is something going wrong in the backend?
I also uploaded a minimal example to this repo: https://github.com/schmitzl/passport-graphql-minimal-example