Search code examples
graphqlsession-cookiesapollo-serverexpress-graphql

Apollo 2.0.0 Graphql cookie session


Can someone help me on this, My setup was as follows prior to Apollo 2.0, I had a server.js in which i used express and graphql-server-express I had a http only cookie session, when a user logs in I set the jwt token as a cookie and it is set in browser as http only. On subsequent request I validate the cookie that the browser passes back. It was all working fine and I could access the token from req.session.token in any other resolver and validate the jwt token saved in the cookie session.

server.js

import express from 'express';
import { graphqlExpress, graphiqlExpress } from 'graphql-server-express';
import { ApolloEngine } from 'apollo-engine';
import bodyParser from 'body-parser';
import cors from 'cors';
import cookieSession from 'cookie-session';
import schema from './schema/';
​
const server = express();
​
server.use(
 cookieSession({
  name: 'session',
  keys: 'k1,k2',
  maxAge: 30 * 60 * 1000,
  domain: '.mydomain.com',
  path: '/',
 }),
);
​
const corsOptions = {
 origin: 'http://local.mydomain.com:3000',
 credentials: true,
 methods: ['GET', 'PUT', 'POST', 'OPTIONS'],
};
​
server.use(cors(corsOptions));
​
server.use(
 '/graphql',
 bodyParser.json(),
 graphqlExpress(req => ({
  schema,
  tracing: true,
  context: { req },
 })),
);
​
if (process.env.NODE_ENV !== 'production') {
 server.use('/graphiql',graphiqlExpress({endpointURL: '/graphql'}));
}
​
const engine = new ApolloEngine({
 apiKey: engineConfig.apiKey,
});
​
engine.listen(
 {
  port: 3000,
  graphqlPaths: ['/graphql'],
  expressApp: server,
 },
 () => {console.log('GraphiQL is now running');},
);

authenticateResolver.js

const authenticateResolver = {
 Query: {
  authenticate: async (root, args, context) => {
   const { req } = context;
​
   const auth = `Basic ${Buffer.from(`${args.username}:${args.password}`).toString('base64')}`;
​
   const axiosResponse = await axios.post("localhot:8080/login, 'true', 
    {
     headers: {
       Authorization: auth,
     },
    });
​
   if (axiosResponse.status === 200 && axiosResponse.data.token) {
    req.session.token = axiosResponse.data.token;
   }
   return {
     status: 200,
   };
 },

But when I upgraded to Apollo 2.0 my server.js code changed, authenticateResolver was as is. I am now unable to access req.session.token in any subsequent requests since the cookie session is not getting set. When I open Developer tools in chrome I cannot see the cookie being set when Authentication is called. What am I doing wrong here ?

server.js # After Apollo 2.0 upgrade ​

import express from 'express';
import { ApolloServer, gql } from 'apollo-server-express';
import cors from 'cors';
import cookieSession from 'cookie-session';
import { mergedTypes, resolvers } from './schema/';
​
const server = express();
​
server.use(
 cookieSession({
  name: 'session',
  keys: 'k1,k2',
  maxAge: 30 * 60 * 1000,
  domain: '.mydomain.com',
  path: '/',
 }),
);
​
const corsOptions = {
 origin: 'http://local.mydomain.com:3000',
 credentials: true,
 methods: ['GET', 'PUT', 'POST', 'OPTIONS'],
};
​
server.use(cors(corsOptions));
​
server.listen({ port: 3000 }, () => { 
 console.log('Server ready');
 console.log('Try your health check at: .well-known/apollo/app-health');
});
​
const apollo = new ApolloServer({
 typeDefs: gql`
  ${mergedTypes}
 `,
 resolvers,
 engine: false,
 context: ({ req }) => ({ req }),
});
​
apollo.applyMiddleware({
 server
});

Solution

  • Yes, If you look at the graphql playground there is a settings option if you click on that you can observe few settings, one of them being "request.credentials": "omit" just change it to "request.credentials": "include" and save settings and it should now work.

    Refer to image

    My code looks as follows as well:

    const app = express()
    
    app.use(
      cookieSession({
        name: 'session',
        keys: corsConfig.cookieSecret.split(','),
        maxAge: 60 * 60 * 1000,
        domain: corsConfig.cookieDomain,
        path: '/',
      })
    )
    
    const corsOptions = {
      origin: corsConfig.corsWhitelist.split(','),
      credentials: true,
      methods: ['GET', 'PUT', 'POST', 'OPTIONS'],
    }
    
    app.use(cors(corsOptions))
    
    const apollo = new ApolloServer({
      typeDefs: gql`
        ${mergedTypes}
      `,
      resolvers,
      engine: false,
      context: ({ req }) => ({ req }),
      tracing: true,
      debug: !process.env.PRODUCTION,
      introspection: !process.env.PRODUCTION,
    })
    
    apollo.applyMiddleware({
      app,
      path: '/',
      cors: corsOptions,
    })
    
    app.listen({ port: engineConfig.port }, () => {
      console.log('🚀 - Server ready')
      console.log('Try your health check at: .well-known/apollo/app-health')
    })