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.
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)
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
ExpressorKoaare built around the notion to only include themiddleware/node_modulesyou 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.