There are many use cases to use getAccessTokenSilently outside of a component (for example, in an Axios Interceptor or an Apollo Client).
It's tempting to ask for the option to pass an Auth0Client instance into the Auth0Provider so that its getTokenSilently method can used outside of the context of a component, eg.
const client = new Auth0Client();
export const getAccessToken = () => client.getTokenSilently();
ReactDOM.render(
<Auth0Provider client={client}>
<App />
</Auth0Provider>,
document.getElementById('app')
);We don't expose the client or allow a custom client to be passed into the Auth0Provider for a couple of reasons:
- We don't think you should export a singleton client from a module and risk sharing the autenticated state between requests in an SSR app - even though you might only be writing a client rendered app.
- The client's methods don't always act the same as the hooks, eg the client's
getTokenSilentlybehaves differently to theuseAuth0hook'sgetAccessTokenSilently, and this is the same (or could be the same in future) for other methods and properties. Having a client and hook in your app would lead to inconsistencies and subtly complex bugs.
Our recommended approach is to stick with React Context API, if you have an Apollo or Axios Client, create a provider for them and nest it in the Auth0Provider so it can have access to the useAuth0 hook to call getAccessTokenSilently eg.
ReactDOM.render(
<React.StrictMode>
<Auth0Provider>
{() => {
const { getAccessTokenSilently } = useAuth0();
const instance = axios.create()
instance.interceptors.request.use(function () {/* use getAccessTokenSilently */});
return (
<AxiosProvider axios={instance}>
<App />
</AxiosProvider>)
}}
</Auth0Provider>
</React.StrictMode>,
document.getElementById('root')
);If you really have to break out of React Context, you can always create a static getAccessToken method (with the above caveats) - you don't need a static client.
const deferred = (() => {
const props = {};
props.promise = new Promise((resolve) => props.resolve = resolve);
return props;
})();
export const getAccessToken = async () => {
const getToken = await deferred.promise;
return getToken();
}
ReactDOM.render(
<Auth0Provider clientId={clientId} domain={domain}>
<Auth0Context.Consumer>
{({ getAccessTokenSilently }: any) => {
deferred.resolve(getAccessTokenSilently);
return <App />;
}}
</Auth0Context.Consumer>
</Auth0Provider>,
document.getElementById('app')
);
I have to agree with @a-type.
This library should be easier to use. There are so many examples of needing access to Auth0 methods outside React components.
I too ended up here from an inherited project where it was not clear at all why they were saving off Auth0 methods to a singleton, only when I went to remove it did I understand why it was needed and I'm shocked and disappointed it doesn't have a better solution than this.
I really think this deserves more thought by the Auth0 team.