Apollo-server: Enable cookie support in apollo-server

Created on 5 Aug 2018  Â·  4Comments  Â·  Source: apollographql/apollo-server

Hello,

I would like to use a cookie based JWT authentication. I migrated to apollo2, but seems like there is no configuration allowing to parse cookies and get them injected in context function req parameter.

Can you please make a fix related to this issue ? I see apollo-server is using express… Can we add the cookie parser middleware as you have done with the cors one ?

Thanks

PS : Using http only cookie instead of Authorization header provide more security. This is a production required feature.

Most helpful comment

@ScreamZ, I'm not an actual contributor to the project, but I understand your concern! I also understand why the authors include CORS by default as Apollo Server most likely will be at a different origin than the client and they'd like to make things simple for developers. This said, the ecosystem surrounding frameworks like Express or Koa are built around the notion to only include the middleware / node_modules you need. One team may want to include a cookie parser in their server, but another team may not. Those other teams wouldn't want extra dependencies in their application.

Reading over the Apollo Server docs, they definitely allow you to meet your use case and allow for additional middleware to be mounted (as also demonstrated from the code sample above), https://www.apollographql.com/docs/apollo-server/api/apollo-server.html#Usage.

All 4 comments

Hi @ScreamZ,

This example (not tested) uses Koa, but you can adjust the below concepts and configure your own middleware on your express app and then use server.applyMiddleware().

import Koa from 'koa'
import koaCors from 'kcors'
import cookie from 'koa-cookie'
import { ApolloServer, gql } from 'apollo-server-koa'

import { fetchUser } from './users'
import { validateToken } from './auth'

const typeDefs = gql`
  type Query {
    hello: String
  }
`

const resolvers = {
  Query: {
    hello: () => 'Hello world!',
  },
}

function authMiddleware() {
  return async function authMiddlewareHandler(ctx, next) {
      try {
        // protect GraphQL endpoint and check if cookie token is valid
        const tokenResponse = await validateToken(ctx.cookie.token)

        if (!tokenResponse.success) {
          ctx.throw(401, 'access_denied')
        } else {
          await next()
        }
      } catch (e) {
        ctx.throw(401, 'access_denied')
      }
   }
}

const app = new Koa()
  // configuring CORS
  .use(koaCors())
  // parses cookies and assigns cookie object to ctx.cookie
  .use(cookie())
  // check if ctx.cookie.token is valid
  .use(authMiddleware())

const server = new ApolloServer({ 
  typeDefs,
  resolvers,
  context: async ({ ctx }) => {
    // if you wanted to fetch full user details and pass it to your resolvers
    const user = await fetchUser(ctx.cookie.token)
    return { user }
  },
}) 

server.applyMiddleware({ app })

app.listen({ port: 4000 }, () =>
  console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`),
)

All right, I'll go that way for the moment, but I saw that you added cors support in main server, I think cookies support would be really nice and pleasant :)
This is almost required all time for a production app (no way to store jwt in storage, this is vulnerable to XSS)

Thanks :)

@ScreamZ, I'm not an actual contributor to the project, but I understand your concern! I also understand why the authors include CORS by default as Apollo Server most likely will be at a different origin than the client and they'd like to make things simple for developers. This said, the ecosystem surrounding frameworks like Express or Koa are built around the notion to only include the middleware / node_modules you need. One team may want to include a cookie parser in their server, but another team may not. Those other teams wouldn't want extra dependencies in their application.

Reading over the Apollo Server docs, they definitely allow you to meet your use case and allow for additional middleware to be mounted (as also demonstrated from the code sample above), https://www.apollographql.com/docs/apollo-server/api/apollo-server.html#Usage.

This works really well. Also includes the upload.
cookies will work HOWEVER I cannot seem to get them to work for mobile devices in the browser...

import withApollo from "next-with-apollo"
import { ApolloClient } from "apollo-client"
import { InMemoryCache } from "apollo-cache-inmemory"
// import { ApolloLink } from "apollo-client-preset"
import { ApolloLink } from "apollo-link"
import { createUploadLink } from "apollo-upload-client"
import { endpoint, prodEndpoint } from "../config"
const tron = "sad because cookies arent being attached for mobile =("

function createClient({ headers }) {
  const authLink = new ApolloLink((operation, forward) => {
    operation.setContext({
      fetchOptions: {
        credentials: "include",
      },
      headers: headers,
    })
    return forward(operation)
  })

  const client = new ApolloClient({
    // ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
    uri: process.env.NODE_ENV === "development" ? endpoint : prodEndpoint,
    link: authLink.concat(
      createUploadLink({
        uri: process.env.NODE_ENV === "development" ? endpoint : prodEndpoint,
      })
    ),
    cache: new InMemoryCache(),
  })
  return client
}

export default withApollo(createClient)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bryanerayner picture bryanerayner  Â·  3Comments

veeramarni picture veeramarni  Â·  3Comments

leinue picture leinue  Â·  3Comments

manuelfink picture manuelfink  Â·  3Comments

mathroc picture mathroc  Â·  3Comments