graphqlapolloapollo-servergraphql-jsapollo-federation

Apollo GraphQL dynamic authenticated subgraphs


I'm building an Apollo Gateway w/ Federated schemas - and I have many subgraphs - each of them has their own authentication token (e.g many REST APIs, each user has his own token saved in the database for each REST API).

I'm fetching the token for each REST API for each user in the Gateway to reduce the overload from each subgraph and to check the permissions on the gateway level, but I'm struggling with how to pass the credentials to each subgraph from the gateway.

I came across this answer, however, here he's building the serviceList himself and I'm using Apollo Federation - and the gateway object doesn't have access to the serviceMap because it is a private under the Typescript definition, also - this is a very hackish way of accomplishing it:

class RequestHander extends RemoteGraphQLDataSource {
    willSendRequest({ request }: { request: GraphQLRequest }) {
        // if request.http.url matches url of a service which you
        // use, add api-key to headers, e.g.
        if (request.http.url === 'http://localhost:3001') {
            request.http.headers.set('api-key', <API_KEY>)
        }
    }
}

const main = () => {
    const gateway = new ApolloGateway({
        buildService: ({ url }) => new RequestHander({ url }),
        serviceList: [
            { name: 'service1', url: 'http://localhost:3001' },
            { name: 'service2', url: 'http://localhost:3002' },
        ],
    })

    const server = new ApolloServer({ gateway })

    void server.listen({ port: 3000 }).then(({ url }) => {
        logger.info(`Apollo Gateway ready at ${url}`)
    })
}

Any best practices or better methods to make dynamically authenticated subgraphs?


Solution

  • My current solution is indeed accessing the private serviceMap entry under the Gateway, as follows:

    for (const [serviceName, dataSource] of Object.entries((<any>gateway).serviceMap)) {
        if ((<any>dataSource).url == request.http?.url) { 
          ... 
        }
    }
    .