Apollo-link: How to access request headers from middleware

Created on 4 Jan 2018  路  7Comments  路  Source: apollographql/apollo-link

Hello there,

I am trying to setup an auth middleware following the example at

https://github.com/apollographql/apollo-client/blob/master/docs/source/recipes/authentication.md

import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';
import { InMemoryCache } from 'apollo-cache-inmemory';

const httpLink = createHttpLink({
  uri: '/graphql',
});

const authLink = setContext((_, { headers }) => {
  // get the authentication token from local storage if it exists
  const token = localStorage.getItem('token');
  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : null,
    }
  }
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
});

The problem is, within the setContext function, I don't have access to headers. It seems the first param is the query, and the second is (previous) context ?

I need to calculate a HMAC header based on the request headers & body, so I would appreciate any tips to help access these.

Thanks !

Most helpful comment

Hi, I just want to share my experience here. I wasted whole day on this and maybe I can help other people not to be stuck. Or point out problems which could occur in the future.

I use aws lambda as backend for graphql server. To sign graphql request with amazon V4 signature, requires exact body, headers, methods etc. . The problem was that req.query.loc.source.body returns YOUR graphql query, but not the actual body what was going to be sent to the server. apollo-link uses print function from graphql/language/printer to parse your query to actual body and it takes req.query as argument. So I ended up using this function to generate body in setContext.

my code for it:

import { print } from 'graphql/language/printer';


const authLink = setContext( async(req, deq) => {

    const query = print(req.query),
                   method = "POST",
                   ...........

    const body = {
        operationName: req.operationName,
        variables: req.variables,
        query: query,
    }

// there are many libraries to sign the request
    const signedRequest = sigV4Client.newClient({.... credentials + body + other info})
        const signedHeaders = signedRequest.headers;

// I had to delete some headers because my server is configured not to accept them
    delete headers['Content-Type']
    delete headers['Accept']

  return {
    headers: {
    accept: 'application/json',
      ...signedHeaders,
    }
  }
});

All 7 comments

thats example what u show is used to prepare request headers, if u want add more just put new item after

authorization: token ? `Bearer ${token}` : null,

works eg. with middleware and after, you have on https://github.com/benawad/slack-clone-client/blob/31_fix_auto_refresh_of_jwt_tokens/src/apollo.js#L11

thank you !

The thing is, I want to calculate an auth header using the headers & body. So I am doing something like,

authorization: calculateAuthHeader(headers, body),

unfortunately both headers and body are nil. (well, I can get the body from req.query.loc.source.body, but I can't find the headers anywhere)

Hello again,

I kind of got away without accessing headers, but I need the body.

req.query.loc.source.body has query body raw format. But apollo is sending something with additional keys like operationName, variables, etc ... Is there a way to access request raw body before request is sent ?

It's easy for headers

const middelwareLink = new ApolloLink((operation, forward)=> {
  console.log('inMiddelware')
  console.log(operation.getContext())  // here!!!
  return forward(operation)
})

We ended up rebuilding the body using query, operationName, and variables found in operation (or request) it would be nice to have direct access to raw request body before it is sent though.

thanks !

Hi, I just want to share my experience here. I wasted whole day on this and maybe I can help other people not to be stuck. Or point out problems which could occur in the future.

I use aws lambda as backend for graphql server. To sign graphql request with amazon V4 signature, requires exact body, headers, methods etc. . The problem was that req.query.loc.source.body returns YOUR graphql query, but not the actual body what was going to be sent to the server. apollo-link uses print function from graphql/language/printer to parse your query to actual body and it takes req.query as argument. So I ended up using this function to generate body in setContext.

my code for it:

import { print } from 'graphql/language/printer';


const authLink = setContext( async(req, deq) => {

    const query = print(req.query),
                   method = "POST",
                   ...........

    const body = {
        operationName: req.operationName,
        variables: req.variables,
        query: query,
    }

// there are many libraries to sign the request
    const signedRequest = sigV4Client.newClient({.... credentials + body + other info})
        const signedHeaders = signedRequest.headers;

// I had to delete some headers because my server is configured not to accept them
    delete headers['Content-Type']
    delete headers['Accept']

  return {
    headers: {
    accept: 'application/json',
      ...signedHeaders,
    }
  }
});

@Nojusle

This is also what we ended up doing.

@apollo-team, this is absolutely necessary for any auth scheme which uses HMAC. Therefore please consider providing a convenience method for accessing (actual) request body.

Thanks !

Was this page helpful?
0 / 5 - 0 ratings