How to use react-auth0-spa with GraphQL?

I’m using the react-auth0-wrapper class in the SPA demo and trying to use it with GraphQL. Specifically, how can I add the token to the GraphQL requests like in the GraphQL demo? The graphql creates an auth class that exposes getIdToken. The SPA wrapper doesn’t have that

const apollo = new ApolloClient({
  uri: 'http://localhost:3001/graphql',
  request: operation => {
    operation.setContext(context => ({
      headers: {
        ...context.headers,
        authorization: auth.getIdToken(),
      },
    }));
  }
})
2 Likes

Bumping this. Spent the last 2 days trying to figure out how to get tokens to my GraphQL provider. I am unable to do it because my ApolloClient isn’t in a functional component or class as all it does is return the client.

1 Like

I meant to add that since my client isn’t made in a Functional Component/Class Component then I can’t call the React Hook that calls for the token.

I had a similar dilemma after following the Auth0 React quick start guide and trying to add Apollo Client. As @TanBeige pointed out it is tricky because the Auth0 hook can only be used from within a functional component but the docs seem to set up the ApolloProvider in the index file.

With a bit of experimentation I managed to get around this by creating a wrapper component which allows me to make use of the useAuth0 hook and asynchronously fetch/attach the token to each request.

I created a new file AuthorizedApolloProvider.tsx :

import { ApolloClient, ApolloProvider, createHttpLink, InMemoryCache } from '@apollo/client';
import { setContext } from '@apollo/link-context';
import React from 'react';

import { useAuth0 } from '../react-auth0-spa';

const AuthorizedApolloProvider = ({ children }) => {
  const { getTokenSilently } = useAuth0();

  const httpLink = createHttpLink({
    uri: 'http://localhost:4000/graphql', // your URI here...
  });

  const authLink = setContext(async () => {
    const token = await getTokenSilently();
    return {
      headers: {
        Authorization: `Bearer ${token}`
      }
    };
  });
  
  const apolloClient = new ApolloClient({
    link: authLink.concat(httpLink),
    cache: new InMemoryCache(),
    connectToDevTools: true
  });

  return (
    <ApolloProvider client={apolloClient}>
      {children}
    </ApolloProvider>
  );
};

export default AuthorizedApolloProvider;

Then in my index.tsx file I wrap App with my new AuthorizedApolloProvider instead of using ApolloProvider directly.

ReactDOM.render(
  <Auth0Provider
    domain={config.domain}
    client_id={config.clientId}
    redirect_uri={window.location.origin}
    audience={config.audience}
    onRedirectCallback={onRedirectCallback}>

      <AuthorizedApolloProvider>
        <App />
      </AuthorizedApolloProvider>
      
  </Auth0Provider>,  
  document.getElementById('root')
);

Note: The above example is using Apollo Client 3 beta, and I had to install @apollo/link-context in addition to @apollo/client . I guess the required imports might be different for versions of Apollo Client.

Thank you @mattwilson1024 ! Do you know the difference between apollo-client and @apollo/client? And if this works with subscriptions as well?

Thanks,
Tan

My code example above is based on Apollo Client 3.0 (worth noting that at the time of writing it’s still in beta). In 3.0 they have changed the packages and made it so that you can import a lot more of the common functionality from a single package. So:

  • @apollo/client is for Apollo Client 3.0
  • apollo-client (plus various other packages) are for Apollo Client 2.x

See https://www.apollographql.com/docs/react/v3.0-beta/migrating/apollo-client-3-migration/#whats-new-in-30.

I’ve not tried subscriptions yet so not sure about that part I’m afraid

1 Like

No issues with the ApolloClient being recreated on each render?