node.jsoauth-2.0asanaasana-connect

How to handle expiration of OAuth access_token using Asana node client?


Using Asana's NodeJS module (https://github.com/Asana/node-asana) with OAuth, how should I handle expiration of the access_token? Does the client provide some mechanism that I should use to detect this? Does it provide something I should use to get a new access_token using the refresh_token? I haven't been able to find any discussion of the refresh_token in the documentation.


I've registered my app and I'm able to successfully get credentials using the Client.app.accessTokenFromCode API. Something like this:

function handleOauthCallback(req, res) {
    var client = Asana.Client.create({
        clientId: CLIENT_ID,
        clientSecret: CLIENT_SECRET,
        redirectUri: computeRedirectUrl(req)
    });
    client.app.accessTokenFromCode(req.query.code).then(function(credentials) {
        // store credentials
    }
}

I'm storing the entire credentials object that comes back from this call and later creating a client using those credentials. Something like this:

var client = Asana.Client.create({
    clientId: CLIENT_ID,
    clientSecret: CLIENT_SECRET,
    redirectUri: computeRedirectUrl(req)
});
var storedCredentials = getStoredCredentials();
client.useOauth({ credentials : storedCredentials });

Now that I've got a client that's initialized with the credentials I got back from Asana (which includes an access_token and refresh_token), how should I handle expiration of the access_token? Do I need to check whether it's still valid myself and ask for a new token using the refresh token? Or will the client handle it for me automatically? If the client handles it, how do I find out when it gets a new access token?

Update

Reading the code, it appears that the client will try to use the refresh token if the access token is no longer valid. But I don't see any kind of notification that I can hook into to find out that there's a new access token. Is there a recommended strategy to handle this?


Solution

  • (I work at Asana). This is a great question, and we should add answers to the documentation.

    The dispatcher can be passed an option called handleUnauthorized which is a callback to run when it gets a 401 (which if you started with good credentials should only happen when your token expires). It's documented in the code.

    The default behavior of this option is to call Dispatcher.maybeReauthorize, which will make the backend request to get a new access token if it has a refresh token.

    So if you just want the dispatcher to transparently refresh the access token, you don't need to do anything, it should "just work"! But if you want to intercept this process, you can pass handleUnauthorized in the dispatch options and then do whatever you want, possibly including calling the default method.

    If you want to see the new access token, well .. the Authenticator class is abstract and we haven't provided a robust way to extract credentials from it; maybe we can add that. If you really need this, you could assume it's the oauth flavor with something like:

    handleUnauthorized: function() {
      return Dispatcher.maybeReauthorize.call(dispatcher).then(
          function(reauthorized) {
            if (reauthorized) {
              onCredentials(dispatcher.authenticator.credentials);
            }
            return reauthorized;
          });
    }
    

    This isn't beautiful, but it should work for you. Just be aware we may evolve this interface a bit over time and you may have to tweak it in the future.