PHP API, Oauth2 workflow

So I’m working on a small integration app with PHP, have installed your library and also implemented it. For the first time authentication, it works fine and also later on it works fine. What I have a problem with is the workflow needed.

After an hour when the token expires the authentication does not work anymore. I’ve noticed there is an implementation for the refresh token, have used that as well but still no luck.

Currently, my workflow is as follows:

  • Print out the authentication link
  • Link redirects back with a code and state parameter
  • On the page if both are present I take the code and use the fetchToken() method to get the token
  • I also use the refreshAccessToken() method to get the refresh token

Now this all works fine and I get retrieve data from the API. The main question that I have is how is the workflow supposed to look like, so I can get data even after an hour or at a later request. Which part should I save in my system and how should I reuse it again later on so I can successfully authenticate again?

Thanks,
Jan

Hello @Jan_Zavrl,

You need to make another call to providing the refresh token (token will be null) to refresh the access token. The refresh tokens remains available for 10 years as I have read

$client = Asana\Client::oauth(array(
        'client_id' => env('CLIENT_ID'),
        'client_secret' => env('CLIENT_SECRET'),
        'redirect_uri' => 'https://example.com',
        'token' => null,
        'refresh_token' => $refreshToken
        ));

   $accessToken = $client->dispatcher->refreshAccessToken(); 

Hope I helped a bit.

So if I understand correctly, once I make the original authentication I get the access token which is valid for 1 hour. Once that is done I use the refreshAccessToken() method with which I get the refresh token which lasts for 10 years. I save the refresh token into my system for future use. Next time I make the request I call the client using your above parameters? ‘token’ being null and ‘refresh_token’ the saved token?

Hi @Jan_Zavrl

What I do is simple, I store two values in the cookies:

  • access token
  • refresh token

my access token has an expiration of 3500 seconds, and the refresh token never expires.

What is do is simple, if I have a valid access token, I use the token; if I don’t (but still have a refresh token) I use the refresh token to create a new access token.

You can dig into the file asanaWorker.class.php I use for a silly project of mine:

@Diakoptis is there a call to check the validity of an access token? So far I have only been able to see that requests fails if the access token is expired, but not to check this beforehand…

Ciao
Carlo

Why even use the access token if it can expire and you can connect just the same with the refresh token? Based on @Diakoptis response he calls the client without the access token. Also, I’m looking into the available dispatcher methods and can see there is a getExpiresInSeconds() method which you can use to see if the access token is still available.

Correct except:

Once that is done I use the refreshAccessToken() method with which I get the refresh token which lasts for 10 years.

you exchange the code with the accessToken (valid for 1 hour) and you get also the refresh token (valid for 10 years)

$accessToken = $client->dispatcher->fetchToken($_GET['code']);
$refreshToken = $client->dispatcher->refreshToken;

when the accessToken expired, you use the refreshToken to get a new accessToken (the code I shared).

expiring the token is a security feature. If a token is compromised, you need to have access to the refresh token to generate a new one.
I believe you can only ask for a new token if you pass null during the initialisation

Is the getExpiresInSeconds available only when you generate the token or even subsequently?

There is a getExpiredInSeconds but I haven’t use it yet. Currently I do the job with the No Authorization error message. When I try it I’ll let you know :slight_smile:

Which call do you use for the No Authorisation?

This is the request fail response for every call that failed to authorize the accessToken.

do you try/catch all the API requests to get it?

Yes. I have a separate class and wrap them all.

The getExpiresInSeconds() method only works when you called the access token because only then will you have the expiry time in the dispatcher. So I’m thinking of saving the current time when I got my first authentication and then on the second request pulling that data, checking if it’s past one hour and then do the logic.

I’ll give this a go this afternoon, will report back how it goes.

The refresh token is indeed used to get new tokens when the one you have expires. Let me share some code. I have been struggling so much with this!

Inside my webhook callback for example, here is what I do:

  • get the token and refresh token from my database
  • authenticate using Asana PHP code
    return Asana\Client::oauth(array(
    ‘client_id’ => $ASANA_CLIENT_ID,
    ‘client_secret’ => $ASANA_CLIENT_SECRET,
    ‘redirect_uri’ => $ASANA_REDIRECT_URI,
    ‘token’ => $token,
    ‘refresh_token’ => $refreshToken,
    ‘state’ => $state
    ));
  • refresh access token (apparently I do it every time, this was easier to code at first)
    $client->dispatcher->refreshAccessToken();
  • and then I can connect to the API

I have spend hours on the whole process this is so hard and confusing :sweat_smile:
Does that help?

1 Like

Yes, this is working now, if anybody will be struggling with this in the future these are the two snippets that work now:

return Client::oauth([
    'client_id' => $this->clientId,
    'client_secret' => $this->clientSecret,
    'redirect_uri' => $this->callbackUrl,
]);

With this, I get the initial connection and then get the access token with fetchToken method. Once I have the access token and refresh token I use this:

return Client::oauth([
    'client_id' => $this->clientId,
    'client_secret' => $this->clientSecret,
    'redirect_uri' => $this->callbackUrl,
    'token' => $token,
    'refresh_token' => $refresh_token,
]);

To get a new connection and then using that I get the new access token.

Now I must say, that the biggest mistake I made was thinking that the method refreshAccessToken will retrieve me the refresh token, but that actually refreshes the access token, figure that. I’m a bit used to the logic that any properties of the class should not be accessed directly from outside the class, but instead should have the get and set methods for that. Guess this is not the case and that is why I got so confused.

So thanks to everyone helping out.

Jan

Hi Jan_Zavrl,

I am using asana > oauth2 from this URL:

But no success, getting errors:

Notice: Undefined index: access_token in /var/www/html/vendor/asana/asana/src/Asana/Dispatcher/OAuthDispatcher.php on line 46

Notice: Undefined index: refresh_token in /var/www/html/vendor/asana/asana/src/Asana/Dispatcher/OAuthDispatcher.php on line 47

Notice: Undefined index: expires_in in /var/www/html/vendor/asana/asana/src/Asana/Dispatcher/OAuthDispatcher.php on line 48
Authorization failed, exiting…

=======

Fatal error: Uncaught exception ‘Exception’ with message ‘OAuthDispatcher: cannot refresh access token without a refresh token.’ in vendor/asana/asana/src/Asana/Dispatcher/OAuthDispatcher.php:56 Stack trace: #0 /var/www/html/myproj/asana_oauth.php(37): Asana\Dispatcher\OAuthDispatcher->refreshAccessToken() #1 {main} thrown in /var/www/html/vendor/asana/asana/src/Asana/Dispatcher/OAuthDispatcher.php on line 56

@Rajendra_Thakur
given that you use https://github.com/Asana/php-asana/blob/master/examples/example-oauth.php can you tell where it fails exactly in the code please?