I am following the same tutorial Fullstack React GraphQL TypeScript Tutorial in Jun 2022. Since 2021, Apollo's GraphQL Playground does not exist- in it's place there is Apollo studio sandbox (https://studio.apollographql.com/sandbox/explorer)
There is no way I could find to set request.credentials to include in the new apollo studio.
After following these threads:
https://community.apollographql.com/t/allow-cookies-to-be-sent-alongside-request/920
and
https://github.com/apollographql/apollo-server/issues/5775
I came to a not-so-great solution, but that works for what I need.
Essentially, in my setup it seems like the session.cookie parameters 'sameSite' and 'secure' need to be different values depending on if you want your front end to add the cookie vs the apollo studio to add the cookie. This is NOT IDEAL - but I could not find any other combinations of parameters that worked for both. So far I've only found mutually exclusive settings.
On my server's index.ts
I use this session setup when I want to set cookie from front-end localhost:3000
app.use(
session({
name: COOKIE_NAME,
store: new RedisStore({ client: redis, disableTouch: true }),
saveUninitialized: false,
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 12, //2 weeks
httpOnly: true,
sameSite: "lax", // sets cookie from frontend localhost:3000
secure: false, // sets cookie from frontend localhost:3000
},
secret: "shhhhdonttell",
resave: false,
})
);
I actually change the session setup if I want to set the cookie and session userId from the apollo studio
I use this session setup when I want to set cookie from backend-end localhost:4000/graphql
app.use(
session({
name: COOKIE_NAME,
store: new RedisStore({ client: redis, disableTouch: true }),
saveUninitialized: false,
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 12, //2 weeks
httpOnly: true,
sameSite: "none", // sets cookie from apollo studio
secure: true, // sets cookie from apollo studio
},
secret: "shhhhdonttell",
resave: false,
})
);
Please comment if you know of a way to use the same settings to allow cookies from both front and backend.
For those of you who are following the tutorial and want more details, here are the other important parts of the setup.
This is my entire index.ts file from backend. Note - I am 8.5 hours into the tutorial - so don't worry if you don't recognize some parts.
import "reflect-metadata";
import { COOKIE_NAME, __prod__ } from "./constants";
import express from "express";
import { ApolloServer } from "apollo-server-express";
import { buildSchema } from "type-graphql";
import { HelloResolver } from "./resolvers/hello";
import { PostResolver } from "./resolvers/post";
import { UserResolver } from "./resolvers/user";
import ioredis from "ioredis";
import session from "express-session";
import connectRedis from "connect-redis";
import { MyContext } from "./types";
import cors from "cors";
import { getDataSource } from "./data-source";
import { Post } from "./entities/Post";
const PORT = 4000;
const main = async () => {
const dbconn = await getDataSource()
if (typeof dbconn === "boolean") return
console.log('starting migrations')
dbconn.runMigrations()
// await Post.delete({})
// const orm = await MikroORM.init(microConfig);
// orm.getMigrator().up();
console.log('migrations finished')
const app = express();
const RedisStore = connectRedis(session);
const redis = new ioredis();
// const redisClient = new redis({ legacyMode: true });
redis.connect().catch((err) => `RedisClient Connect error: ${err}`);
!__prod__ && app.set("trust proxy", 1);
app.use(
cors({
origin: ["http://localhost:3000", "http://localhost:4000/graphql", "https://studio.apollographql.com",],
credentials: true,
})
);
app.use(
session({
name: COOKIE_NAME,
store: new RedisStore({ client: redis, disableTouch: true }),
saveUninitialized: false,
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 12, //2 weeks
httpOnly: true,
sameSite: "lax",
secure: __prod__,
},
secret: "shhhhdonttell",
resave: false,
})
);
// app.use(
// session({
// name: COOKIE_NAME,
// store: new RedisStore({ client: redis, disableTouch: true }),
// saveUninitialized: false,
// cookie: {
// maxAge: 1000 * 60 * 60 * 24 * 12, //2 weeks
// httpOnly: true,
// // sameSite: "lax", // front end
// // secure: __prod__, //true in production, is can be false for frontend
// sameSite: "none", //csrf //must be nne for apollo sandbox
// secure: true, //true in production, false on localhost // must be true for apollo sandbox even in dev
// },
// secret: "shhhhdonttell",
// resave: false,
// })
// );
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [HelloResolver, PostResolver, UserResolver],
validate: false,
}),
context: ({ req, res }): MyContext => ({
dbconn,
req,
res,
redis,
}),
});
await apolloServer.start();
apolloServer.applyMiddleware({
app,
cors: false,
// cors: {
// // origin: "http://localhost:3000",
// origin: [
// "http://localhost:3000",
// "https://studio.apollographql.com",
// "http://localhost:4000/graphql",
// ],
// credentials: true,
// },
});
app.listen(PORT, () => {
console.log(`server started on localhost:${PORT}`);
});
};
main().catch((err) => {
console.error(err);
});
Here is my data-source (the new way to make typeORM connection!)
import { Post } from "./entities/Post";
import { Users } from "./entities/Users";
import { DataSource } from "typeorm";
import path from "path"
import "reflect-metadata";
import { Upvote } from "./entities/Upvote";
export async function getDataSource() {
const typeormDataSource = new DataSource({
type: "postgres",
host: "localhost",
port: 5432,
username: "nicole",
password: "yourpassword",
database: "bendb2", //your dbname
logging: false,
synchronize: true,
entities: [Post, Users, Upvote],//take out entites you have't made yet.
subscribers: [],
migrations: [path.join(__dirname, "./migrations/*")],
})
let datasource = await typeormDataSource.initialize().catch(err => {
console.error(err)
console.log("Database connection NOT initialized")
return false
})
return datasource
}
in the createUrqlClient.tsx front end file, I have added
export const createUrqlClient = (ssrExchange: any) => ({
url: "http://localhost:4000/graphql",
fetchOptions: {
credentials: "include" as const,
},
exchanges: [...]
Here is a snapshot of the settings needed in apollo studio. To open these settings, click on the settings/gear icon at the top left inside the SANDBOX input.

make sure to add 'x-forwarded-proto' 'https' to the Shared Headers.