Vue Apollo with Authorization Code Grant Flow with PKCE

Hey!

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?

Thank you for your help!

Hi @tim-newnow,

Welcome to the Community!

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.

Thanks,
Dan

Hey, thank you :slight_smile:

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 :smiley:

Thank you!
Tim

I believe I have found the way to do it:

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.

    // HTTP Auth header injection
    authLink = setContext((_, { headers }) => {
      const authorization = getAuth(tokenName)
      const authorizationHeader = authorization ? { authorization } : {}
      return {
        headers: {
          ...headers,
          ...authorizationHeader,
        },
      }
    })

So by making this function return and handle a promise from getAuth, it should be possible to use the async get token silently function from the sdk.

I will talk to Akryum or submit a pull request.

Then in the vue apollo options, we can use:

  // Override the way the Authorization header is set
  getAuth: async () => {
    const token = await getInstance().getTokenSilently();
    return token ? `Bearer ${token}` : "";
  }

Token lifetimes depend on conditions, and are open to some customizations.

How does the sdk handle the token retrieval, is it cached, what happens when it expires?

The SDK caches the token. Silent auth (getTokenSilently), can be used to get a new token.

Glad you found a solution!

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.