Hello I'm trying to use Auth0's spa example with react and I'm using the useAuth0 hook, I'm also using Apollo client to make my queries and I need to get the token and set it in the request, however I haven't been able to set it.
I would be very grateful if someone could point me in the right direction.
I've tried to use the context property in the query/mutation component but I couldn't figure it out nor find information about how to use it.
I had the same dilemma, especially since 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.
The way I tackled this issue is by editing an article I found online from https://hasura.io/
In other words, it uses react's useContext()
hook and useEffect()
to check and get the jwt token by using auth0's getTokenSilently()
function.
I will just write the parts that are relevant:
import React, { FC, ReactNode } from 'react'
import { useAuth0 } from '@auth0/auth0-react'
import { ApolloProvider } from 'react-apollo'
import { ApolloClient, HttpLink, InMemoryCache } from 'apollo-boost'
import { setContext } from 'apollo-link-context'
import { useState, useEffect } from 'react'
const httpLink = new HttpLink({
uri: 'yourdomain.test/graphql',
})
const Page: FC<{}> = ({children }) => {
const [accessToken, setAccessToken] = useState('')
const [client, setClient] = useState() as [ApolloClient<any>, any] // that could be better, actually if you have suggestions they are welcome
const { getAccessTokenSilently, isLoading } = useAuth0()
// get access token
useEffect(() => {
const getAccessToken = async () => {
try {
const token = await getAccessTokenSilently()
setAccessToken(token)
} catch (e) {
console.log(e)
}
}
getAccessToken()
}, [])
useEffect(() => {
const authLink = setContext((_, { headers }) => {
const token = accessToken
if (token) {
return {
headers: {
...headers,
authorization: `Bearer ${token}`,
},
}
} else {
return {
headers: {
...headers,
},
}
}
})
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
})
setClient(client)
}, [accessToken])
if (!client) {
return <h1>Loading...</h1>
}
return (
<ApolloProvider client={client}>
{...children}
</ApolloProvider>
)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With