Forward Subgraph set-cookie Header to Gateway to Client

Hello,

I have a subgraph microservice that handles sessions. We store our sessions via cookies that the subgraph creates, and should set it via the set-cookie header. Only issue is my gateway does not seem to be forwarding the set-cookie header from the subgraph to the client.

Here is the code for my gateway

const { ApolloServer } = require('apollo-server');
const { ApolloGateway, RemoteGraphQLDataSource } = require('@apollo/gateway');
const { readFileSync } = require('fs');

const supergraphSdl = readFileSync('./gateway/supergraph.graphql').toString();

class CookieDataSource extends RemoteGraphQLDataSource {
  didReceiveResponse({ response, request, context }) {
    const cookie = response.http.headers.get('set-cookie');
    console.log("Cookie:", cookie)
    if (cookie) {
      context.cookies = cookie;
    }

    return response;
  }
}

const gateway = new ApolloGateway({
  supergraphSdl,
  buildService({url}) {
    return new CookieDataSource({url});
  }
});

const server = new ApolloServer({
  gateway,
  cors: {
    origin: ["http://localhost:3000", "https://studio.apollographql.com"],
    credentials: true
  },
  csrfPrevention: true,
});

server.listen().then(({ url }) => {
  console.log(`🚀 Gateway ready at ${url}`);
}).catch(err => {console.error(err)});

version info
@apollo/gateway”: “^2.1.2”,
“apollo-server”: “^3.10.2”,

I can confirm that the subgraph is sending back a set-cookie header, however, it is not being passed through to the client.

Thank you!

I ended up resolving the issue by creating both a gateway datasource that added context value. Then, pass the header from the subgraph context value to the response header.

import { GatewayGraphQLResponse, GatewayGraphQLRequestContext } from '@apollo/server-gateway-interface';
import { RemoteGraphQLDataSource } from '@apollo/gateway';
import { ApolloServerPlugin, GraphQLRequestContext, GraphQLRequestListener } from '@apollo/server';

interface ServerContext {
  passthrough_cookies?: string
}

export class CookieProcessorDataSource extends RemoteGraphQLDataSource {
  didReceiveResponse({response, context}: Required<Pick<GatewayGraphQLRequestContext<Record<string, any>>, 'request' | 'response' | 'context'>>): GatewayGraphQLResponse | Promise<GatewayGraphQLResponse> {
    context.passthrough_cookies = response.http?.headers.get('set-cookie');
    return response;
  }
}
  
export class CookieServerListener implements GraphQLRequestListener<ServerContext> {
  public willSendResponse({contextValue, response}: GraphQLRequestContext<ServerContext>): Promise<void> {
    if (contextValue.passthrough_cookies !== undefined) {
      response.http.headers.set('set-cookie', contextValue.passthrough_cookies);
    }

    return Promise.resolve()
  }
}

export class CookieServerPlugin implements ApolloServerPlugin<ServerContext> {
  async requestDidStart() {
    return new CookieServerListener();
  }
}