Nextjs with ApolloClient with basic routing to separate graphql server

Viewed 538

I am building a Nextjs App that has a separate GraphQL server endpoint. I wanted to be able to use ApolloClient (React) for this project, just to gain familiarity with the technology.

I used the Nextjs with-apollo example to get started. My understanding is that it creates a separate ApolloClient for Server side and Client side GraphQL requests. My current problem is that the GraphQL endpoint I want to access requires Authorization (meaning I need to pass it a Bearer API token) I don't want to leave that API token in the NEXT_PUBLIC environment variables for fear that someone might be able to find it.

So my question is: What is the best approach here? Do i:

  1. Send the requests to my Nextjs server before sending them to the separate GraphQL endpoint to conceal my environment variable? Can I do that with @apollo/client HTTPLink? Can I still use useQuery or do I need to use something like axios?

  2. Only create 1 ApolloClient (on the server, with the credentials) and pass that to the browser as well? How would I do that?

  3. Create a REST endpoint that my client-side Next Application can query to get the credentials?

  4. Is there a canonical way of getting secrets to the client without exposing them?

  5. Some other method...

Reference:

// lib/apolloClient.js
// ... imports ignored ...

let apolloClient;

function createApolloClient() {
  // this line is the line in question... 
  // potentially exposing my API_TOKEN because NEXT_PUBLIC_ env variables 
  // are exposed on both the server and the client
  let apiToken = process.env.NEXT_PUBLIC_API_TOKEN
  return new ApolloClient({
    ssrMode: typeof window === "undefined", // set to true for SSR
    uri: "https://my-separate-graphql-server/endpoint",
    headers: {
      Authorization: 'Bearer ' + apiToken,
    },
    cache: new InMemoryCache(),
  });
}

export function initializeApollo(initialState = null) {
  const _apolloClient = apolloClient ?? createApolloClient();
  // If your page has Next.js data fetching methods that use Apollo Client,
  // the initial state gets hydrated here
  if (initialState) {
    // Get existing cache, loaded during client side data fetching
    const existingCache = _apolloClient.extract();

    // Restore the cache using the data passed from
    // getStaticProps/getServerSideProps combined with the existing cached data
    _apolloClient.cache.restore({ ...existingCache, ...initialState });
  }

  // For SSG and SSR always create a new Apollo Client
  if (typeof window === "undefined") return _apolloClient;

  // Create the Apollo Client once in the client
  if (!apolloClient) apolloClient = _apolloClient;
  return _apolloClient;
}

export function useApollo(initialState) {
  const store = useMemo(() => initializeApollo(initialState), [initialState]);
  return store;
}
0 Answers
Related