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.
index.ts(server setup)
import {MikroORM} from "@mikro-orm/core";
import microConfig from "./mikro-orm.config";
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";
const { createClient } = require("redis")
import session from "express-session";
import connectRedis from "connect-redis";
import {__prod__} from "./constants";
import {MyContext} from "./types";
const main=async () => {
const orm=await MikroORM.init(microConfig)
await orm.getMigrator().up()
const app=express();
const RedisStore = connectRedis(session);
const redisClient = createClient({
legacyMode: true
});
redisClient.connect().catch(console.error)
app.set('trust proxy', !__prod__)
app.use(
session({
name: "qid",
store: new RedisStore({
client: redisClient,
disableTouch: true,
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10, // 10 years
httpOnly: true,
sameSite: "none", // csrf
secure: __prod__, // cookie only works in https
},
saveUninitialized: false,
secret: "qowiueojwojfalksdjoqiwueo",
resave: false,
})
);
const apolloServer =new ApolloServer({
schema:await buildSchema({
resolvers:[HelloResolver,PostResolver,UserResolver],
validate:false
}),
context:({req,res}):MyContext => ({em:orm.em,req,res})
})
await apolloServer.start();
const corsOptions={origin:["https://studio.apollographql.com", "http://localhost:4000"],credentials:true}
apolloServer.applyMiddleware({app,cors:corsOptions})
app.listen(4000,()=>{
console.log("server listening on port 4000")
})
}
main()
User.ts(my resolver)
import {
Resolver,
Mutation,
Arg,
InputType,
Field,
Ctx,
ObjectType,
} from "type-graphql";
import { MyContext } from "../types";
import { User } from "../entities/User";
import argon2 from "argon2";
@InputType()
class UsernamePasswordInput {
@Field()
username: string;
@Field()
password: string;
}
@ObjectType()
class FieldError {
@Field()
field: string;
@Field()
message: string;
}
@ObjectType()
class UserResponse {
@Field(() => [FieldError], { nullable: true })
errors?: FieldError[];
@Field(() => User, { nullable: true })
user?: User;
}
@Resolver()
export class UserResolver {
@Mutation(() => UserResponse)
async register(
@Arg("options") options: UsernamePasswordInput,
@Ctx() { em }: MyContext
): Promise<UserResponse> {
if (options.username.length <= 2) {
return {
errors: [
{
field: "username",
message: "length must be greater than 2",
},
],
};
}
if (options.password.length <= 2) {
return {
errors: [
{
field: "password",
message: "length must be greater than 2",
},
],
};
}
const hashedPassword = await argon2.hash(options.password);
const user = em.create(User, {
username: options.username,
password: hashedPassword,
});
try {
await em.persistAndFlush(user);
} catch (err) {
//|| err.detail.includes("already exists")) {
// duplicate username error
if (err.code === "23505") {
return {
errors: [
{
field: "username",
message: "username already taken",
},
],
};
}
}
return { user };
}
@Mutation(() => UserResponse)
async login(
@Arg("options") options: UsernamePasswordInput,
@Ctx() { em,req }: MyContext
): Promise<UserResponse> {
const user = await em.findOne(User, { username: options.username });
if (!user) {
return {
errors: [
{
field: "username",
message: "that username doesn't exist",
},
],
};
}
const valid = await argon2.verify(user.password, options.password);
if (!valid) {
return {
errors: [
{
field: "password",
message: "incorrect password",
},
],
};
}
req.session.userId = user.id;
return {
user,
};
}
}
3
Answers
I have changed the secure key to be true and it works
First of all, you have to add two lines in your index.ts
And configure Apollo graphql studio-> go to Connection Settings -> Edit -> Include Cookies
Make sure to add this header : x-forwarded-proto: https
I looked into their docs and its recommended to use Apollo 4+
Setup below will probably help you setup endpoint to
http://localhost:4000/graphql
instead ofhttps://studio.apollographql.com/
Pass it to
plugins
innew ApolloServer({})