StravaPHP icon indicating copy to clipboard operation
StravaPHP copied to clipboard

Issue with refresh page: Required option not passed: "access_token"

Open ghost opened this issue 1 year ago • 1 comments

Hi - firstly, thank you for making this repository.

I have a simple page below - api-001.php:

<?php
require '../../vendor/autoload.php';

use Strava\API\OAuth;
use Strava\API\Exception;
use Strava\API\Client;
use Strava\API\Service\REST;

try {
    $options = [
        'clientId'     => 123456,
        'clientSecret' => '9876543210',
        'redirectUri'  => 'http://localhost/strava/api-001.php'
    ];
    $oauth = new OAuth($options);

    if (!isset($_GET['code'])) {
        print '<a href="'.$oauth->getAuthorizationUrl([
            // Uncomment required scopes.
            'scope' => [
                'read',
                'read_all',
                'profile:read_all',
                'profile:write',
                'activity:read',
                'activity:read_all',
                'activity:write',
            ]
        ]).'">Connect</a>';
		
    } else {
		
        $token = $oauth->getAccessToken('authorization_code', [
            'code' => $_GET['code']
        ]);
		
        print $token->getToken();
		
		try {
			$adapter = new \GuzzleHttp\Client(['base_uri' => 'https://www.strava.com/api/v3/']);
			$service = new REST($token->getToken(), $adapter);  // Define your user token here.
			$client = new Client($service);
			$athlete = $client->getAthlete();
			print_r($athlete);
			$activities = $client->getAthleteActivities();
		} catch(Exception $e) {
			print $e->getMessage();
		}

    }
} catch(Exception $e) {
    print $e->getMessage();
}
?>

When I first access it, I click Connect and click Authorize.

I'm redirected to http://localhost/strava/api-001.php and can see my athlete info.

However, if I click F5 on the browser, I end up with this error:

PHP Fatal error:  Uncaught InvalidArgumentException: Required option not passed: "access_token" in C:\Data\Websites\vendor\league\oauth2-client\src\Token\AccessToken.php:96
Stack trace:
#0 C:\Data\Websites\vendor\league\oauth2-client\src\Provider\AbstractProvider.php(844): League\OAuth2\Client\Token\AccessToken->__construct(Array)
#1 C:\Data\Websites\vendor\league\oauth2-client\src\Provider\AbstractProvider.php(642): League\OAuth2\Client\Provider\AbstractProvider->createAccessToken(Array, Object(League\OAuth2\Client\Grant\AuthorizationCode))
#2 C:\Data\Websites\strava\api-001.php(33): League\OAuth2\Client\Provider\AbstractProvider->getAccessToken(Object(League\OAuth2\Client\Grant\AuthorizationCode), Array)
#3 {main}
  thrown in C:\Data\Websites\vendor\league\oauth2-client\src\Token\AccessToken.php on line 96

I realise the documentation on the main page for this repository has 2 sections:

First, authorisation and authentication

Then, call your API method!

I tried putting the code for the second part in a separate page, but then it errors on this line:

$service = new REST($token->getToken(), $adapter);  // Define your user token here.

Because I haven't defined $token which is why in my quoted code above I redirect to the same starting page api-001.php as that already has $token defined.

I thought maybe I can store $token in localStorage but I am not sure how I'd store $token in localStorage as it is an array I think, not just a variable with a single value.

Sorry for probably overlooking something very basic - but I cannot see how to set things up so that I can refresh the page, otherwise I have to go back to click Connect each time.

I checked these issues:

https://github.com/basvandorst/StravaPHP/issues/92 https://github.com/basvandorst/StravaPHP/issues/57

But can't work it out.

Sorry if it is something simple, I have basic PHP skills but am trying to work out what to do.

Thanks

ghost avatar Mar 30 '24 13:03 ghost

Same issue when I tested this sunday. Hi @vredeling 👋 :)

COil avatar Feb 11 '25 17:02 COil

Hello, I take some time to answer to this issue because I also lost some time on this:

When doing the first call, the $code is what is returned by Strava as a GET parameter after the user has given it permission to use his Strava account :

You can use this code to get an access token:

return $this->oAuth->getAccessToken('authorization_code', ['code' => $code]);

This returns an object implementing the AccessTokenInterface. When getting this object, you have to store some information to the user account like this :

It is the access token string that you need to store in the user account to further request calls to the API.

            $user->setStravaAccessToken($accessToken->getToken())
            ->setStravaRefreshToken($accessToken->getRefreshToken())
            ->setStravaExpires(new \DateTimeImmutable()->setTimestamp((int) $accessToken->getExpires()))

When using this access_code, you should test first whether it is expired or not, thanks to the $expires_at value. If the access token is expired, you must refresh it. I am not sure this part is handled by this library, for now, I do it manually with an HTTP POST call (it is a Symfony HTTP client in this case)

        $response = $this->stravaClient->request('POST', 'api/v3/oauth/token', [
            'body' => [
                'client_id' => $this->stravaClientId,
                'client_secret' => $this->stravaClientSecret,
                'grant_type' => 'refresh_token',
                'refresh_token' => (string) $user->getStravaRefreshToken(),
            ],
        ]);

This returns a response like this:

final class RefreshTokenResponse
{
    public string $access_token;
    public int $expires_at;
    public int $expires_in;
    public string $refresh_token;
}

Then you can replace the different values associated to the user account, and you can make other API calls until the next expiration date. Then you go back to the refresh step.

COil avatar Mar 15 '25 08:03 COil

Hi there, I just confirm the bug. The same symptoms. I get this once per 5-10 authorizations:

{
    "message": "Bad Request",
    "errors":
    [
        {
            "resource": "AuthorizationCode",
            "field": "code",
            "code": "invalid"
        }
    ]
}

I'm interested in why it happens, because we get this code from Strava anyway. So Strava gives the code and rejects it a few seconds later?

absoftware avatar Mar 28 '25 17:03 absoftware

I spent on this entire day almost. But I have a proof of concept why it doesn't work:

  • We receive the code
  • We use it in the request to https://www.strava.com/oauth/token
  • We receive invalid for the code and the lib throws exception Required option not passed: "access_token"

The reason of this that we process this request too fast, so it is not propagated in the Strava services (probably some independent services processing auth codes).

So if we repeat request https://www.strava.com/oauth/token once again with the same code after ~2 seconds, then it works, despite that we used this code once before, but it hasn't been registered yet in the Strava's OAuth service.

absoftware avatar Mar 29 '25 03:03 absoftware

Well, are you sure this is the same problem? As explained in my answer, I don't have this problem anymore now that I correclty store the information received at 1st call.

COil avatar Mar 29 '25 06:03 COil

@COil Yes, you are right. It is not the same problem, but symptoms are the same. In my case I do everything all right, but despite that Strava returns me this error as well. I proved in my code that they can return the code too quickly. So I delay processing around 2 seconds and it works much better. I hope it will be useful for people finding this issue here.

absoftware avatar Mar 29 '25 20:03 absoftware