title: Apollo Client Async Refresh Token
body: <p>I have been struggling to asynchronously refresh the token in Apollo client, when an Unauthenticated error occurs. 
  I've reviewed several resources on this, like StackOverflow answers, <a href="https://github.com/apollographql/apollo-link/issues/646" rel="nofollow noreferrer">this</a> Github issue and <a href="https://able.bio/AnasT/apollo-graphql-async-access-token-refresh--470t1c8" rel="nofollow noreferrer">this</a> blog post. </p>
  
  <p>The main thing is to wait before retrying the failed request, after the new token is obtained. Reading the comments in the blog above and the comments in the Github issue, it seems that many people have successfully managed to solve this, however, I get the data with the new token, after a retry is done, which means that the retry is still done with the old token, so it fails.</p>
  
  <p>Here's the function that executes the refresh mutation. </p>
  
  <pre><code>
  export const getNewToken = (client) =&gt; {
    const refreshToken = getRefreshToken();
    return client.mutate({
      mutation: REFRESH_TOKEN,
      variables: { refreshToken },
    });
  };
  </code></pre>
  
  <p>Here's the Auth Link, I do a <code>console.log</code> of the token, to know which token is used.</p>
  
  <pre><code>const authLink = setContext((_, { headers }) =&gt; {
    // get the authentication token from local storage if it exists
    const token = localStorage.getItem("token");
    console.log("Token in auth link: ", token);
    return {
      headers: {
        ...headers,
        authorization: token ? `JWT ${token}` : "",
      },
    };
  });
  </code></pre>
  
  <p>Then in Apollo's <code>onError</code> function, I tried to recreate the third example in the linked blog above:</p>
  
  <pre><code>if (token &amp;&amp; refreshToken) {
    return fromPromise(
      getNewToken(client)
        .then(({ data: { refreshToken } }) =&gt; {
          console.log("Promise data: ", refreshToken);
          localStorage.setItem("token", refreshToken.token);
          localStorage.setItem("refreshToken", refreshToken.refreshToken);
          return refreshToken.token;
        })
        .catch((error) =&gt; {
          // Handle token refresh errors e.g clear stored tokens, redirect to login, ...
          console.log("Error after setting token: ", error);
          return;
        })
    )
      .filter((value) =&gt; {
        console.log("In filter: ", value);
        return Boolean(value);
      })
      .flatMap(() =&gt; {
        console.log("In flat map");
        // retry the request, returning the new observable
        return forward(operation);
      });
  }
  </code></pre>
  
  <p>There are two problems with the execution of this:
  1. The <code>filter</code> and <code>flatMap</code> functions aren't called at all. 
  2. The new token is received AFTER <code>authLink</code> has logged a call with the old token. Which means that <code>forward(operation)</code> doesn't wait for the new token.</p>
  
  <p>I also tried the concurrent request from the linked blog. There's more going on in there, so here's the whole <code>src/index.js</code> in a Gist
  <a href="https://gist.github.com/bzhr/531e1c25a4960fcd06ec06d8b21f143b" rel="nofollow noreferrer">https://gist.github.com/bzhr/531e1c25a4960fcd06ec06d8b21f143b</a></p>
  
  <p>Here <code>forward$.flatMap</code> doesn't get called AT ALL. And the same problems as the example above.</p>
  
  <p>I am not sure where's my error, since many people have commented on the blog that it's working for them. I've checked my code multiple times. I need some help in debugging this. The main thing being to wait with the retry, until the new token is ready. </p>