Search code examples
authorizationapollonext.jsreact-apolloserver-side-rendering

Apollo client + Next.js - Adding Authorization token to client request


GOAL

I want to populate my Authorization header with an access token. I want to store that access token in the Apollo cache as Auth0 explicitly state not to store access tokens in local storage (I don't know why the Apollo Client docs seem to think it's okay).

Failing that, I want to store my access token securely and be able to add it to each Apollo Client request to the Apollo Server.

const apolloClient = withApollo(({ctx, headers, initialState}) => {
  const cache = new InMemoryCache();

  // Code here to access local cache.

  return new ApolloClient({

    cache,
    link: new HttpLink({
      uri: <apollo server endpoint>,
      headers: {
        Authorization: `Bearer ${accessToken}`,
        'Access-Control-Allow-Origin': 'http://localhost:3000/',
        ...headers
      },
      credentials: 'include'
    }),
    typeDefs,
    resolvers
  })
})

class MyApp extends App {
  render() {
    const { Component, pageProps, apollo } = this.props;


    return (
      <ApolloProvider client={apollo}>
        <Component {...pageProps} />
      </ApolloProvider>
    );
  }
}

export default apolloClient(MyApp);

TRIED

  • I've tried to access localStorage from within the withApollo function but it is SSR'd so I'm unable to access that. I was going to use the localStorage to set a boolean to check in the withApollo function so it'll know the access token has been added to the apollo cache after the redirect.
  • I've tried just using the cache with a key storing a boolean to check if the user has signed in which is set in the same function where the access token. If that is true I'd access the access token key and add that to the Authorization header. But I was getting issues with setting the initial state overriding the cache set in sign in function.

OTHER IDEAS

  • I thought I could pass the access token through in the ctx argument, but I'm not familiar enough with Next.js to figure out if that's valid way to do it.

  • I thought I could pass in a props to the withApollo function from a component, but that doesn't seem like it'd be possible.

QUESTIONS

  • What is the best way to store the access key so as to add it to the Apollo Client with each request?
  • I noticed some people are using a fetch polyfill, would that be appropriate for this situation? If so, how would that work?
  • How does the withApollo HOC work and why is it needed to work with Next.js? I've read some of the code behind this, but I don't fundamentally understand why it is needed.

Solution

  • I was able to find a solution to my question. I just didn't fully understand the Apollo Client and how to use all of the required packages.

    SOLUTION

    I used setContext from the apollo-link-context library. It's part of the link set of libraries that Apollo Client offers to customise the network request after a graphql operation has started. I set the header in the setContext function. Like so:

    const authLink = setContext((_, { headers }) => {
      // It is also possible to use the local storage method in here.
      const data = cache.readQuery({
        query: ACCESS_TOKEN
      });
    
      return {
        headers: {
          ...headers,
          authorization: accessToken ? `Bearer ${data.accessToken}` : ""
        }
      }
    });
    

    The following is outside the withApollo function.

    const httpLink = new HttpLink({
      uri: '<server uri>',
    });
    

    The following is inside the withApollo function.

    return new ApolloClient({
        cache,
        link: authLink.concat(httpLink),
        typeDefs,
        resolvers
      })
    

    The docs for how setContext are here and the docs for the `apollo-link-context' are here.