I'm trying to make a client-side request to the GitHub graphql API using Apollo Client, but there's a 401 authentication issue I haven't been able to resolve.
I've swapped out the query with one to a different API that doesn't require authentication and have confirmed that it works as expected.
I can make successful requests server-side using getServerSideProps
(it's a Next.js app), so I know the credentials are fine.
What am I missing here? Is this a CORS issue? (e.g. How to fix authentication error when querying Yelp GraphQL API using Apollo Client)
Thanks in advance. Code below, and reference to method here: https://www.apollographql.com/blog/apollo-client/next-js/next-js-getting-started/.
The handle for the client is defined in apollo-client.js
:
import { ApolloClient, createHttpLink, InMemoryCache } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
export const getApolloClient = () => {
const httpLink = createHttpLink({
uri: "https://api.github.com/graphql",
});
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: `Bearer ${process.env.GITHUB_ACCESS_TOKEN}`,
},
};
});
return new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
});
};
I've wrapped the root component in the Apollo context provider (pages/_app.jsx
):
import { ApolloProvider } from "@apollo/client";
import { getApolloClient } from "../apollo-client";
const client = getApolloClient();
function MyApp({ Component, pageProps }) {
return (
<ApolloProvider client={client}>
<Component {...pageProps} />
</ApolloProvider>
);
}
export default MyApp;
A sample query here in Component.jsx
:
import { useQuery } from "@apollo/client";
import { gql } from "@apollo/client";
const QUERY = gql`
query GetRepository {
repository(owner: "facebook", name: "react") {
id
nameWithOwner
description
url
}
}
`;
const Component = () => {
const { data, loading, error } = useQuery(QUERY);
if (loading) {
return (...);
}
if (error) {
console.error(error);
return null;
}
return <div>...</div>;
};
export { Component };
useQuery()
returns "Response not successful: Received status code 401"
As @juliomalves pointed out, this issue can be solved by exposing the GITHUB_ACCESS_TOKEN
to the browser, by prepending with NEXT_PUBLIC_
. Since I didn't want the token exposed to the browser, the working solution was to make the request through a Next API route. The implementation closely follows the method at the link below for fetching data on the server:
https://www.apollographql.com/blog/apollo-client/next-js/next-js-getting-started/
I.e., in /pages/api/endpoint.js, something like:
import { getApolloClient } from "../apollo-client";
export default function handler(req, res) {
const client = getApolloClient();
try {
const { data } = await client.query({
query: gql`
...
`,
});
res.status(200).json({ data });
} catch (e) {
res.status(400).json({ error: e.message });
}
}
where the necessary authorization headers are defined in getApolloClient
:
import { ApolloClient, createHttpLink, InMemoryCache } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
export const getApolloClient = () => {
const httpLink = createHttpLink({
uri: "https://api.github.com/graphql",
});
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: `Bearer ${process.env.GITHUB_ACCESS_TOKEN}`,
},
};
});
return new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
});
};