Cookie not shown/stored in the browser

Hi,

I have a question regarding cookies. Here I’m using apollo-server-express, express-session and redis for all of the authentication process. My problem with it is that in apollo studio my cookie, which is created inside the UserResolver under the mutation login, isn’t shown there. Hence why the query me returns null. Is also worth mentioning I’m not getting any errors while doing all of this.

For better understanding I’ll leave some screenshots below.

I hope someone can help me out here. Thanks in advance.

P.S. Sorry for the cluttered screenshots. Could only attach one file because I just created this account.

Some notes:

  • main function = index file
  • login mutation = logs in user and should create a cookie
  • me query = should check if user is logged in
  • (rest of the screenshots are executions of login, me and some settings)
1 Like

Hi there! Hugely appreciate the screenshots, really helps clear up uncertainty :pray:

The short answer is hardcoding the cookie’s secure field to be true + using the workaround described here (bottom) should make the connection work

The longer explanation is

  • having cookies work from one site to another requires sameSite: none (which I see has already been set)
  • sameSite: none requires secure: true (which I see is currently dependent on the environment)
  • there’s an open issue on express-session where it doesn’t send the set-header header when encountering a request made to a server running with “secure: true” running on a non-https endpoint even for localhost
  • setting trust proxy to true on the server, and sending x-forwarded-proto to https as the header will trick it into setting the cookie

There’s a different workaround suggested by express-session’s maintainer to overwrite the value of req.secure using object.defineProperty on your server, should also work

Hope that helps!

1 Like

Hi, first of all I hugely appreciate the well explained answer you gave me. If I’m being honest here I have not idea how to set/use those tips you just mentioned especially those on this paragraph:
“setting trust proxy to true on the server, and sending x-forwarded-proto to https as the header will trick it into setting the cookie”.
Could you provide me a code example how that would work and if it’s not much to ask for also show me where I have to add this inside my code.
And lastly I just wanted to mention that I now hard coded the true value on secure but unfortunately it still doesn’t work as expected.

Best Regards,
Nevzat

Yup no problem!

Try adding this line before your first app.use (line 22)

app.set('trust proxy', process.env.NODE_ENV !== 'production')

Then in Studio’s Explorer’s headers tab, add this header x-forwarded-proto with a value of https

Lemme know if that works!

It’s working now. Thank you :grinning: .

1 Like

@Chang I have faced the same issue like this one but your solution Doesn’t work for me

@solomon_mulatu have you been able to solve this problem? i’m looking for a solution as well.

I have Fixed My Problem By This parts

here is the updated section

async function startApolloServer() {
// Required logic for integrating with Express
const app = express();
const RedisStore = connectRedis(session);
const redis = new Redis();
const httpServer = http.createServer(app);

app.set('trust proxy', process.env.NODE_ENV !== 'production')

//if you access it from localhost uncomment below lines
const whitelist = ['http://localhost:3000', 'https://studio.apollographql.com'];
let corsOptions = {
    origin: function (origin, callback) {
        if (whitelist.indexOf(origin) !== -1) {
            callback(null, true)
        } else {
            callback(new Error('Not allowed by CORS'))
        }
    }
}
app.use(cors({ credentials: true, origin: corsOptions }));


app.use(
    session({
        name: "qid",
        store: new RedisStore({
            client: redis,
            disableTouch: true,
        }),
        cookie: {
            maxAge: 1000 * 60 * 60 * 24 * 365 * 10, // 10 years
            //if you access it from localhost uncomment below lines
            // httpOnly: true,
            //please un comment below codes if u run it production level
            // sameSite: 'none', // csrf
            // secure: false, // cookie only works in https
            // secure:false,
        },
        saveUninitialized: false,
        secret: "qowiueojwojfalksdjoqiwueo",
        resave: false,
    })
);
// Same ApolloServer initialization as before, plus the drain plugin.
const server = new ApolloServer({
    schema:await buildSchema({
        resolvers:[HelloResolver,ClientResolver,ProjectResolver],
        validate:false
    }),
    context:({req,res}):MyContext => ({req,res,redis}),

    // csrfPrevention: true,
    // cache: 'bounded',
    // plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});

// More required logic for integrating with Express
await server.start();
const corsOpt={origin:"https://studio.apollographql.com",credentials:true}


server.applyMiddleware({
    app,
    cors:false,//change it to corsOpt if u want in localhost
    // By default, apollo-server hosts its GraphQL endpoint at the
    // server root. However, *other* Apollo Server packages host it at
    // /graphql. Optionally provide this to match apollo-server.
});

// Modified server startup
await new Promise<void>(resolve => httpServer.listen({ port: 4000 }, resolve));
// app.listen(4000,()=>{
//     console.log("server listening on port 4000")
// })
await connectDB()
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`);

}
startApolloServer().catch(error=>{
console.log(error)
})

@solomon_mulatu Thank you, turns out it wasn’t my problem at all, i was using new apollographql studio and it didn’t work there, but in old environment on http://localhost:4000/graphql it works just fine. You can define it in plugins it like so: Migrating to Apollo Server 3 - Apollo GraphQL Docs
Hopefully, it’ll help those who are stuck here like i did lol.