1

I am currently trying to setup the Twinfield API. I believe I am almost there, almost... I managed to retrieve an accessToken and a refreshToken, but somehow this works only on the first page load. After reloading the page I get the 'invalid_grant' error. I am not exactly sure what goes wrong, because it actually is working on the first page load.

Here is my code:

        $provider    = new OAuthProvider([
        'clientId'     => 'clientId',
        'clientSecret' => 'clientSecret',
        'redirectUri'  => 'http://127.0.0.1:8000'
    ]);

    if (!isset($_GET['code'])) {
        $options = [
            'scope' => ['twf.user', 'twf.organisation', 'twf.organisationUser', 'offline_access', 'openid']
        ];
        $authorizationUrl = $provider->getAuthorizationUrl($options);
        $_SESSION['oauth2state'] = $provider->getState();
        header('Location: ' . $authorizationUrl);
        exit;
    } elseif (empty($_GET['state']) || (isset($_SESSION['oauth2state']) && $_GET['state'] !== $_SESSION['oauth2state'])) {
        if (isset($_SESSION['oauth2state'])) {
            unset($_SESSION['oauth2state']);
        }
        exit('Invalid state');
    } else {
        try {

            $accessToken = $provider->getAccessToken('authorization_code', [
                'code' => $_GET['code']
            ]);
            
            $refreshToken = $accessToken->getRefreshToken();

            echo 'Access Token: ' . $accessToken->getToken() . "<br>";
            echo 'Refresh Token: ' . $accessToken->getRefreshToken() . "<br>";
            echo 'Expired in: ' . $accessToken->getExpires() . "<br>";
            echo 'Already expired? ' . ($accessToken->hasExpired() ? 'expired' : 'not expired') . "<br>";

            $office       = \PhpTwinfield\Office::fromCode("someOfficeCode");
            $connection  = new \PhpTwinfield\Secure\OpenIdConnectAuthentication($provider, $refreshToken, $office);

           // $offices = $officeApiConnector->listAllWithoutOfficeCode();

        } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
            // Failed to get the access token or user details.
            exit($e->getMessage() . ' error');
        }

I hope someone can tell me more about what I have been doing wrong. Thanks for the help already.

Tom Roskam
  • 23
  • 5
  • I figured out that it would probably has something to do with the fact that the authorization code is set once and then the accesToken & refreshToken gets initiliazed after that. And on the page reload the 'if' is skipped and the accessToken & refreshToken gets initialized again. Although no access is granted because these tokens do not match the authorization code due to the fact that the authorization code is not update. Someone who experience with this kind of issue? – Tom Roskam May 11 '21 at 07:47
  • Authorization code is actually not allowed to be used more than once... So I will need to retrieve a new one every time the page reloads. And then with the new code retrieve a new accessToken to retrieve a new refreshToken. – Tom Roskam May 12 '21 at 07:31

1 Answers1

0

I used a session counter to make sure a new authorization code is requested every time the page gets refreshed. This way the authorization code always matches the access token and refresh Token.

<?php


namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use PhpTwinfield\ApiConnectors\CustomerApiConnector;
use PhpTwinfield\Secure\Provider\OAuthProvider;
use PhpTwinfield\Secure\OpenIdConnectAuthentication;


  class TWFconnector
  {
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        session_start();
        if (!isset($_SESSION['arr']['counter'])) {
            $_SESSION['arr']['counter'] = 0;
        } else {
            $_SESSION['arr']['counter']++;
        }

    $twin_client_id = '';
    $twin_client_secret = '';
    $twin_client_uri = '';

    $provider    = new OAuthProvider([
        'clientId'     => $twin_client_id,
        'clientSecret' => $twin_client_secret,
        'redirectUri'  => $twin_client_uri,
    ]);

    if (!isset($_GET['code'])) {
        $options = [
            'scope' => ['twf.user', 'twf.organisation', 
    'twf.organisationUser', 'offline_access', 'openid']
        ];

        $authorizationUrl = $provider->getAuthorizationUrl($options);

        header('Location: ' . $authorizationUrl);
        $_SESSION['arr']['counter'] = 0;
    } elseif($_SESSION['arr']['counter'] > 1) {
        header('Location: http://127.0.0.1:8000/');
    } else {
        $accessToken = $provider->getAccessToken('authorization_code', [
            'code' => $_GET['code']
        ]);

        $refreshToken = $accessToken->getRefreshToken();

        $office       = \PhpTwinfield\Office::fromCode("");
        $connection = new OpenIdConnectAuthentication($provider, 
        $refreshToken, $office);

            print_r($connection);
        }
        return $next($request);
    }
}
Tom Roskam
  • 23
  • 5