I am currently integration Auth0 using the new spa sdk. The issue I am facing is, that retrieving the access token is an async operation using this flow. So basically, before every request, I would need to retrieve the token.
Vue Apollo on the other hand only allows to set up the token synchronously. I have already checked, if there is an easy way to make the Apollo Client to accept a promise for the authorization header, but that does not seem to be the case.
What is the best way to tackle this issue?
What I have tried is to setup a watcher for isAuthenticated, retrieve the token and set it into local storage. However as far as I understand, this is not how it is meant, as the token has to be fetched before every request. Also that results in a race condition, as the query in the component might be fired, before the token is retrieved.
Is there a way to use the PKCE flow in my case, or do I have to revert to the implicit flow?
First, you should not store tokens in localstorage or session storage, as they can be vulnerable to xss attacks. Also, you should not have to request a new token before every API call. You can persist the token in memory, and only have to request a new one on login, page refresh, or when the token is expired. I am not familiar with Apollo, but I think it should work like a typical Vue app unless I am missing something. If this doesn’t cover it please provide us with some code to look at how you have things set up.
Not persisiting the token makes perfect sense, however the apollo graphql client or at least the vue implementation kind of relies on it. This is the default function, which fetches the token:
function defaultGetAuth (tokenName) {
if (typeof window !== 'undefined') {
// get the authentication token from local storage if it exists
const token = window.localStorage.getItem(tokenName)
// return the headers to the context so httpLink can read them
return token ? `Bearer ${token}` : ''
}
}
It can be overridden in the options, however it does not handle promises. I believe it is called every time a request is made and not once when initializing, so I can work around the promise problem. But that leaves me with a race condition.
My flow so far is, that I log in and use the AuthGuard in the router. What I can think of right now is, if I postpone calling next() in the AuthGuard until the access token is fetched, all API requests should be able to use the access token. However, this does not seem to be a good solution, as the handling of an expired token would be troublesome.
So basically, the only viable way to do it, is to get the token before every Request, like in the examples or to use the implicit flow and store the token. Getting the token before every request (from the sdk) might be problematic, as I would have to fork and alter the used graphql libs.
I will need to read up on the code grant flow again. The questions I currently have are:
How long is the access token valid after requesting it?
How does the sdk handle the token retrieval, is it cached, what happens when it expires?
If you have any more ideas that could lead me into a clever direction, please throw them at me
The setContext function takes a function that returns either an object or a promise that returns an object to set the new context of a request.
It receives two arguments: the GraphQL request being executed, and the previous context. This link makes it easy to perform async look up of things like authentication tokens and more!
So it does support a promise. However the glue code in vue apollo does not.