I am having trouble while trying to use custom header parameter in apollo server. I have an apollo server as below:
import { ApolloServer } from 'apollo-server-lambda'
import { ApolloGateway, IntrospectAndCompose, GraphQLDataSourceProcessOptions, RemoteGraphQLDataSource } from '@apollo/gateway'
import { ApolloServerPluginLandingPageGraphQLPlayground } from 'apollo-server-core'
import { GraphQLRequest } from 'apollo-server-types'
import { SignatureV4 } from '@aws-sdk/signature-v4'
import { Sha256 } from '@aws-crypto/sha256-js'
import { OutgoingHttpHeader } from 'http'
import { defaultProvider } from '@aws-sdk/credential-provider-node'
import { HttpRequest } from '@aws-sdk/protocol-http'
class AuthenticatedDataSource extends RemoteGraphQLDataSource {
/**
* Adds the necessary IAM Authorization headers for AppSync requests
* @param request The request to Authorize
* @returns The headers to pass through to the request
*/
private async getAWSCustomHeaders(request: GraphQLRequest): Promise<{
[key: string]: OutgoingHttpHeader | undefined
}> {
const { http, ...requestWithoutHttp } = request
if (!http) return {}
const url = new URL(http.url)
//check local env
if(url.host.match(/localhost:20002/)) return {'x-api-key':'da2-fakeApiId123456'}
// If the graph service is not AppSync, we should not sign these request.
if (!url.host.match(/appsync-api/)) return {}
const httpRequest = new HttpRequest({
hostname: url.hostname,
path: url.pathname,
method: http.method,
headers: {
Host: url.host,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestWithoutHttp),
})
const signedRequest = await new SignatureV4({
region: 'eu-west-1',
credentials: defaultProvider(),
service: 'appsync',
sha256: Sha256,
}).sign(httpRequest)
return signedRequest.headers || {}
}
/**
* Customize the request to AppSync
* @param options The options to send with the request
*/
public async willSendRequest({ request, context }: GraphQLDataSourceProcessOptions) {
const customHeaders = await this.getAWSCustomHeaders(request)
if (customHeaders) {
Object.keys(customHeaders).forEach((h) => {
request.http?.headers.set(h, customHeaders[h] as string)
})
}
// context not available when introspecting
if (context.event)
Object.keys(context.event.requestContext.authorizer.lambda).forEach((h) => {
request.http?.headers.set(h, context.event.requestContext.authorizer.lambda[h] as string)
})
}
}
const server = new ApolloServer({
gateway: new ApolloGateway({
buildService({ url }) {
return new AuthenticatedDataSource({ url })
},
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
{ name: 'CONFIGURATIONSERVICE', url: process.env.CONFIGURATION_SERVICE_API_URL }
]
})
}),
debug: true,
context: ({ event, context, express}) => ({
headers: event.headers,
functionName: context.functionName,
event,
context,
expressRequest: express.req,
}),
introspection: true,
plugins: [ApolloServerPluginLandingPageGraphQLPlayground()],
})
exports.handler = server.createHandler({
expressGetMiddlewareOptions: {
cors: {
origin: '*',
}
}
})
When I try to execute configurationservice via playground on port 3000, I realized that I do not x-api-key header parameter and therefore I get 401 authorization. I do not understand the reason of missing header parameter that I already added in the codebase and any help would be appreciated. Thank you!
Ok I noticed that I can also add header parameters via playground application. Now it returns no authorization error.