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 !
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 !
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.bodyreturns YOUR graphql query, but not the actual body what was going to be sent to the server.apollo-linkusesprintfunction fromgraphql/language/printerto parse your query to actual body and it takesreq.queryas argument. So I ended up using this function to generate body insetContext.my code for it: