Apollo-server: passport.js + apollo-server-express drop session

Created on 20 Aug 2019  路  9Comments  路  Source: apollographql/apollo-server

if you use passport.js

const app = express();
app.use(session({
    secret: 'test',
}));
app.use(passport.initialize());
app.use(passport.session());
const server = new ApolloServer({
    typeDefs,
    resolvers,
    context: ({ req }) => {
        const user = req.user;

        console.log({ user, 'req.session': req.session });

        return {
            user,
            orm,
            dataloader: compose(orm),
        };
    },
});

app.use('/graphql', (req, res, next) => {
    console.log({
        url: req.protocol + '://' + req.get('host') + req.originalUrl,
        user: req.user,
        sessionID: req.sessionID,
        session: req.session,
        cookie: JSON.stringify(req.cookie),
    });

    return next();
});
server.applyMiddleware({ app, path: '/graphql' });

if i comment out server.applyMiddleware({ app, path: '/graphql' });,
passport js session is present, otherwise not

if session would be present, it would able to restore user

full PR: https://github.com/eugene-matvejev/node-explorer/pull/73

Most helpful comment

@jonesmac I was so close to implementing your workaround since it's been 3 days that I've been trying to figure out what the heck is wrong with my code why session cookies are not appearing on front-end but being saved in a store e.g in my case Redis. So the issue in my case is I need to also set the credentials: include in Apollo Client

I have posted my answer here for the front-end: https://github.com/apollographql/apollo-client/issues/4190#issuecomment-540023803

As for my back-end, it's like this:

```js
const corsOptions = {
origin: ['http://localhost:5000', /.myproject.com$/],
credentials: true,
};

app.use(cors(corsOptions));

// setup session handling options
const sessionOptions = {
name: config.sessionStore.name,
secret: config.sessionStore.secret,
store: new RedisStore({ client: redisDB, prefix: config.sessionStore.redisSessionIdPrefix }),
resave: false,
saveUninitialized: false,
cookie: {
maxAge: config.sessionStore.lifetime,
sameSite: true,
secure: process.env.NODE_ENV === 'production',
},
};
app.use(session(sessionOptions));

const apolloServer = new ApolloServer({
typeDefs,
resolvers,
context: ({ req, res }) => ({
session: req.session,
redis: redisDB,
}),
playground:
process.env.NODE_ENV === 'production'
? false
: {
settings: {
'request.credentials': 'include',
},
},
});

apolloServer.applyMiddleware({ app, path: '/graphql', cors: false });

All 9 comments

I'm also seeing this issue. It doesn't seem like passport session is known to apollo's applyMiddleware

Any update?

My issue was in the graphql playground. So what I ended up doing was creating a session for a user in postman, then appending that session id to a header which I could control in playground. Then in the context function, I read the header value and looked up the valid session from store so I could append the user object to context. Not the cleanest but finally let me have the user object in context so my resolvers could work as if there was a valid session.

I think the fundamental issues is that playground doesn't have a good way to initiate a session and I'm not entirely sure its within its scope to do so.

@jonesmac I was so close to implementing your workaround since it's been 3 days that I've been trying to figure out what the heck is wrong with my code why session cookies are not appearing on front-end but being saved in a store e.g in my case Redis. So the issue in my case is I need to also set the credentials: include in Apollo Client

I have posted my answer here for the front-end: https://github.com/apollographql/apollo-client/issues/4190#issuecomment-540023803

As for my back-end, it's like this:

```js
const corsOptions = {
origin: ['http://localhost:5000', /.myproject.com$/],
credentials: true,
};

app.use(cors(corsOptions));

// setup session handling options
const sessionOptions = {
name: config.sessionStore.name,
secret: config.sessionStore.secret,
store: new RedisStore({ client: redisDB, prefix: config.sessionStore.redisSessionIdPrefix }),
resave: false,
saveUninitialized: false,
cookie: {
maxAge: config.sessionStore.lifetime,
sameSite: true,
secure: process.env.NODE_ENV === 'production',
},
};
app.use(session(sessionOptions));

const apolloServer = new ApolloServer({
typeDefs,
resolvers,
context: ({ req, res }) => ({
session: req.session,
redis: redisDB,
}),
playground:
process.env.NODE_ENV === 'production'
? false
: {
settings: {
'request.credentials': 'include',
},
},
});

apolloServer.applyMiddleware({ app, path: '/graphql', cors: false });

If anyone is looking for a working example using Apollo server and Passport.js here are one without and one with graphql-passport. There is also a couple of blog posts linked there if you want a more detailed explanation.

arvi's solution worked for me. Apparently, at line:

apolloServer.applyMiddleware({ app, path: '/graphql', cors: false });

cors: false is a crucial setting

I have the same issue. Setting cors to false obviously solves the problem, but how will the server secure client-server communication with cors set to false?

I had my cors originally set to the recommended option setting in numerous documentations, yet nothing works.

const corsOptions = { credentials: true, origin: '*', }

What is the working option setting?

@jonesmac I was so close to implementing your workaround since it's been 3 days that I've been trying to figure out what the heck is wrong with my code why session cookies are not appearing on front-end but being saved in a store e.g in my case Redis. So the issue in my case is I need to also set the credentials: include in Apollo Client

I have posted my answer here for the front-end: apollographql/apollo-client#4190 (comment)

As for my back-end, it's like this:

const corsOptions = {
  origin: ['http://localhost:5000', /\.myproject\.com$/],
  credentials: true,
};

app.use(cors(corsOptions));

// setup session handling options
const sessionOptions = {
  name: config.sessionStore.name,
  secret: config.sessionStore.secret,
  store: new RedisStore({ client: redisDB, prefix: config.sessionStore.redisSessionIdPrefix }),
  resave: false,
  saveUninitialized: false,
  cookie: {
    maxAge: config.sessionStore.lifetime,
    sameSite: true,
    secure: process.env.NODE_ENV === 'production',
  },
};
app.use(session(sessionOptions));


const apolloServer = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req, res }) => ({
    session: req.session,
    redis: redisDB,
  }),
  playground:
    process.env.NODE_ENV === 'production'
      ? false
      : {
        settings: {
          'request.credentials': 'include',
        },
      },
});

apolloServer.applyMiddleware({ app, path: '/graphql', cors: false });

My Dear Lord this got me out of a 4 hours bug hole. Thank you very much.

I see you have the apollo-server cors set to false. It also works fine with values like { credentials: true, origin: '*' }, but to work in tests also set the following to express

app.set('trust proxy', 1)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

stevezau picture stevezau  路  3Comments

manuelfink picture manuelfink  路  3Comments

dbrrt picture dbrrt  路  3Comments

bchehraz picture bchehraz  路  3Comments

veeramarni picture veeramarni  路  3Comments