Expected Behavior
I'm using npm cookie-parser to send back cookies in response from my Apollo server to the client (Apollo Client in case it matters).
Here is the relevant code:
// Verify auth token and refresh if needed
const getMe = async (req, res, next) => {
// Get auth token from cookies
let token = req.headers['x-token']
// Go to next if no auth token provided
if (!token) {
return next()
}
// Attempt to verify auth token
try {
const me = jwt.verify(token, process.env.SECRET)
// Define 'me' context
req.me = me
}
catch (e) {
// If auth token not verified, get refresh token from cookies
const refreshToken = req.headers['x-token-refresh']
// Go to next if no refresh token provided
if (!refreshToken) {
return next()
}
// Get new auth token using refresh token
const newToken = await getNewAuthToken(
refreshToken,
models,
process.env.SECRET
)
// Return new auth token in cookie :::: **THIS IS THE PART THAT DOESN'T WORK**
if (newToken.token) {
res.cookie('x-token', newToken.token, { httpOnly: true })
res.cookie('test-cookie', 'test-value', { httpOnly: true })
}
// Define 'me' context
req.me = newToken.user
}
// Go to next
return next()
}
// Add getMe as middleware
app.use(getMe)
// Create Apollo Server
const server = new ApolloServer({
introspection: true,
playground: true,
typeDefs: schema,
resolvers,
formatError: error => {
const message = error.message
.replace('SequelizeValidationError: ', '')
.replace('Validation error: ', '')
return {
...error,
message,
}
},
context: async ({ req, connection, res }) => {
if (connection) {
return {
models,
}
}
if (req) {
return {
models,
me: req.me,
secret: process.env.SECRET,
res
}
}
},
})
I have verified that everything above is working correctly except for the highlighted section with res.cookie().
It's able to get the tokens, authenticate the auth token, refresh the auth token using the refresh token if the auth token is expired, and define 'me' in context.
I also have a resolver that returns cookies when users first sign-in:
signIn: async (
parent,
{ login, password },
{ models, secret, res },
) => {
// Find user
const user = await models.User.findByLogin(login)
// If username not found
if (!user) {
throw new UserInputError(
'No user found with this login credentials.',
)
}
// If incorrect password
const isValid = await user.validatePassword(password)
if (!isValid) {
throw new AuthenticationError('No user found with this login credentials.')
}
// Get auth and refresh tokens
const [token, refreshToken] = await createTokens(user, secret)
// Send back tokens in cookies as response
res.cookie('x-token', token, { maxAge: 60 * 60 * 24 * 30, httpOnly: true })
res.cookie('x-token-refresh', refreshToken, { maxAge: 60 * 60 * 24 * 30, httpOnly: true })
// Return tokens
return { token, refreshToken }
},
This works perfectly. Once a user is signed in it adds the new tokens to the user's cookies. Nothing is done on the client side to add the cookies, it's all done server-side using res.cookie().
The expected behaviour is that when getMe() runs, res.cookie() should have the same result as res.cookie() that's used in the resolver. That is, it should update the user's cookies with the new auth token (and a test token that I'm using for debugging purposes).
Actual Behavior
When the auth token is expired and a new one is generated using the refresh token, res.cookie() does NOT send back the updated cookies to the client.
It seems that Apollo Server's context: ( { res } ) overwrites express's response or completely ignores it. How do I get this to work?
I also have a similar issue. Basically, I have the token in my response headers but there was actually no cookies were sent back to the clients. To make sure, I also check the Application tab in Chrome Dev Tool but nothing found.

I haven't investigated further as I'm not setting cookies on the client side instead of sending them from the server, but I believe this issue could have something to do with server-side rendering on the client (in my case, next.js). I'll leave this open in case someone comes up with a solution.
I have the same issue.. any news?
+1
@nghitrum
Hi had I simmilar problem this has solved my issue:
https://stackoverflow.com/questions/59021384/how-to-pass-cookie-from-apollo-server-to-apollo-clenet
+1
+1 Any fix or update for this issue?
I have the same issue when trying to integrate apollo server with next.js and next-iron-session.
Updated:
@nghitrum
Hi had I simmilar problem this has solved my issue:
https://stackoverflow.com/questions/59021384/how-to-pass-cookie-from-apollo-server-to-apollo-clenet
I follow the above link, and it works.
There are two important parts I have to change in my code.
return new ApolloClient({
ssrMode: typeof window === 'undefined',
link: new HttpLink({
uri: process.env.NEXT_PUBLIC_GRAPHQL_END_POINT,
credentials: 'include', \\ changed from 'same-origin'
}),
cache: new InMemoryCache(),
});
app.use(
cors({
origin: 'http://localhost:3001', \\ changed from true
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
credentials: true,
}),
);
Same issue with apollo-server
context.res.clearCookie(process.env.REFRESH_TOKEN_NAME!);
doesn't seem to work with clearing cookies. Also it feels really hacky grabbing cookies right now. With apollo-express I could do req.cookies[] now I have to do something like this.
```
const header = context.req.headers.cookie
var cookies = header.split(/[;] */).reduce(function(result: any, pairStr: any) {
var arr = pairStr.split('=');
if (arr.length === 2) { result[arr[0]] = arr[1]; }
return result;
}, {});
console.log(cookies);
const token = cookies[process.env.REFRESH_TOKEN_NAME!];
```
The cookies implementation feels like an afterthought and it's not really setup to handle a real-world app.. unless there is something I'm missing. This feels super important since almost every auth system uses cookies with a refresh token.
Most helpful comment
I have the same issue.. any news?