graphql-engine: Hasura doesn't forward Set-Cookie headers set by remote schemas

Hasura should forward Set-Cookie headers back to the client that are set in Remote Schemas, so that the consumer of the GraphQL API receives them.

  • In order to use cookie-based authentication with Hasura, we need to make sure Cookie: headers are successfully passed to the GraphQL endpoint, so our auth webhook can extract useful information and pass in X-Hasura-* headers back to Hasura.
  • One of the primary reasons to use cookies is the HttpOnly flag, which prevents against vendor javascript running on the same page from stealing our sessions.
  • If Set-Cookie: headers don’t come from the same origin as Hasura, something like credentials: 'include' is necessary for cookies to actually be included in GraphQL requests, at least over HTTP (Queries and Mutations).
  • Unfortunately, WebSockets don’t seem to have any ability to credentials: 'include' and simply will not pass cookies from different origins no matter what, which means that there is currently no way to use http-only cookie-based authentication and subscriptions at the same time with Hasura.
  • Manually adding the Cookie: header to the WebSocket client could be an option, but we lose the ability to use HttpOnly cookies as client-side javascript would be required to parse them to build this header.
  • This also allows a cleaner front-end coding experience; all calls can be done via GraphQL.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 2
  • Comments: 23 (12 by maintainers)

Commits related to this issue

Most upvoted comments

@campie I was wondering if you have an example of cookie auth via auth webhook like you described?

Gotcha. Here’s some thoughts:

  1. It’s unfortunate that this wouldn’t work over ws, but I’m not sure I follow why this is an issue; the auth webhook is transport-dependent as well, isn’t it? Seems like documentation is the way to solve this part (and something I’d be happy to contribute via PR).

Your second point is interesting. Multiple Set-Cookie headers are absolutely fine in an HTTP response; however, there may be clashes if they share the same cookie name. RFC 6265 says:

Servers SHOULD NOT include more than one Set-Cookie header field in the same response with the same cookie-name. (See Section 5.2 for how user agents handle this case.) (https://tools.ietf.org/html/rfc6265#section-4.1.1)

The suggested client behaviour can be found in Section 5.3. My interpretation of the algorithm in this section is that later Set-Cookie headers with the same cookie-name should override earlier ones in the client’s cookie store. My suggestion is that the headers should be returned in the same order as the client sent them in, in order to allow developers to express ordering via the mutation / query they send to Hasura. Given the different specs for different headers, a whitelist of proxy-able headers probably makes sense to make sure Hasura can properly merge / overwrite depending on whether multiple versions of the same response header are allowed in the spec.

So in your example, both Set-Cookie headers would be passed back to the GraphQL client; this behaviour is consistent with the Set-Cookie RFC.

@sastraxi There are couple of problems with forwarding the remote server’s headers to the client. So we haven’t merged this yet.

  1. This is transport dependent. i.e, only if you make the mutation over http this comes into picture. If the same mutation happens over websocket, there is no way to send the response headers
  2. What should the behavior be when the mutation uses fields from different remote servers (which we’ll support in the near future). For example,
mutation m {
  login(..args..)
  register_device(..args..)
}

login is by remote schema ‘a’, and ‘register_device’ is by remote schema ‘b’. What should the behavior be in this case when both the servers respond with a Set-Cookie header?