phpoauth-2.0xero-api

Xero OAuth2 Questions


I have migrated my website to Xero 2.0 and it works, for creating Invoices. However after a few hours i have to reauthorise by clicking on the https://something.com/xero-oauth2/authorization.php file in the browser, reconnecting to the Xero account, otherwise my customers see something similar to the below ...

Fatal error: Uncaught BadMethodCallException: Required parameter not passed: "refresh_token" in /var/www/vhosts/something.com/httpdocs/xero-oauth2/vendor/league/oauth2-client/src/Tool/RequiredParameterTrait.php:35 Stack trace: #0 /var/www/vhosts/something.com/httpdocs/xero-oauth2/vendor/league/oauth2-client/src/Tool/RequiredParameterTrait.php(53): League\OAuth2\Client\Grant\AbstractGrant->checkRequiredParameter('refresh_token', Array) #1 /var/www/vhosts/nasschools.org.uk/httpdocs/xero-oauth2/vendor/league/oauth2-client/src/Grant/AbstractGrant.php(76): League\OAuth2\Client\Grant\AbstractGrant->checkRequiredParameters(Array, Array) #2 /var/www/vhosts/something.com/httpdocs/xero-oauth2/vendor/league/oauth2-client/src/Provider/AbstractProvider.php(535): League\OAuth2\Client\Grant\AbstractGrant->prepareRequestParameters(Array, Array) #3 /var/www/vhosts/something.com/httpdocs/xero-oauth2/createInvoice.php(160): League\OAuth2\Client\Provider\AbstractProvider->getAccessToken(Object(League\OAuth2\Client\Grant\Refre in /var/www/vhosts/something.com/httpdocs/xero-oauth2/vendor/league/oauth2-client/src/Tool/RequiredParameterTrait.php on line 35

Is there anything clearly wrong with this?

            <?php 

            $storage = new StorageClass();
            $xeroTenantId = (string)$storage->getSession()['tenant_id'];

            if ($storage->getHasExpired()) {
                $provider = new \League\OAuth2\Client\Provider\GenericProvider([
                    'clientId' => 'XXXXXX',
                    'clientSecret' => 'XXXXXX',
                    'redirectUri' => 'https://something.com/xero-oauth2/callback.php',
                    'urlAuthorize' => 'https://login.xero.com/identity/connect/authorize',
                    'urlAccessToken' => 'https://identity.xero.com/connect/token',
                    'urlResourceOwnerDetails' => 'https://api.xero.com/api.xro/2.0/Organisation'
                ]);

                $newAccessToken = $provider->getAccessToken('refresh_token', [
                    'refresh_token' => $storage->getRefreshToken()
                ]);

                // Save my token, expiration and refresh token
                $storage->setToken(
                    $newAccessToken->getToken(),
                    $newAccessToken->getExpires(),
                    $xeroTenantId,
                    $newAccessToken->getRefreshToken(),
                    $newAccessToken->getValues()["id_token"]);
            }

            // Configure OAuth2 access token for authorization: OAuth2
            $config = XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken((string)$storage->getSession()['token']);
            $config->setHost("https://api.xero.com/api.xro/2.0");        

            $apiInstance = new XeroAPI\XeroPHP\Api\AccountingApi(
              new GuzzleHttp\Client(),
              $config
            );

            $xero_tenant_id = $xeroTenantId; // string | Xero identifier for Tenant

            // \XeroAPI\XeroPHP\Models\Accounting\Invoices | Invoices with an array of invoice objects in body of request
            $summarize_errors = true; // bool | If false return 200 OK and mix of successfully created objects and any with validation errors
            $unitdp = 4; // int | e.g. unitdp=4 – (Unit Decimal Places) You can opt in to use four decimal places for unit amounts


            $purchaseNumber = str_replace("&", "&amp;", $_SESSION['purchasenumber']);
            $schoolOrGname = str_replace("&", "&amp;", $_SESSION['schoolorgname1']);
            $billingEmail = str_replace("&", "&amp;", $_SESSION['billingemail']);
            $billingAddress = str_replace("&", "&amp;", $_SESSION['billingaddress']);
            $billingCity = str_replace("&", "&amp;", $_SESSION['billingcity']);
            $billingPostalCode = str_replace("&", "&amp;", $_SESSION['billingpostcode']);
            $billingFullName = str_replace("&", "&amp;", $_SESSION['billingfullname']);
            $date = str_replace("&", "&amp;", $_SESSION['now']);
            $dueDate = str_replace("&", "&amp;", $_SESSION['thirty']);
            $eventTitle = str_replace("&", "&amp;", $_SESSION['eventtitle']);
            $eventPrice = str_replace("&", "&amp;", $_SESSION['eventprice']);


            $address = new Address();
            $address->setAddressType('POBOX');
            $address->setAddressLine1($billingAddress);
            $address->setCity($billingCity);
            $address->setPostalCode($billingPostalCode);
            $address->setAttentionTo($billingFullName);

            $contact = new Contact();
            $contact->setName($schoolOrGname)
                ->setContactStatus('ACTIVE')
                ->setEmailAddress($billingEmail)
                ->setAddresses([$address]);

            $lineItem = new LineItem();
            $lineItem->setDescription($eventTitle)
                ->setQuantity(1)
                ->setAccountCode(4002)
                ->setUnitAmount($eventPrice)
                ->setTaxAmount(0)
                ->setTaxType('NONE');

            $invoice = new Invoice();
            $invoice->setDate($date)
                ->setDueDate($dueDate)
                ->setLineAmountTypes('Exclusive')
                ->setType('ACCREC')
                ->setReference($_SESSION['purchasenumber'])
                ->setStatus('AUTHORISED')
                ->setContact($contact)
                ->setLineItems([$lineItem]);

            try {
                $result = $apiInstance->createInvoices($xero_tenant_id, $invoice, $summarize_errors, $unitdp);
                header("Location: https://something.com/order-confirmation/");
            } catch (Exception $e) {

                print_r($e);
                echo '<br/><br/>Exception when calling AccountingApi->createInvoices: ', $e->getMessage(), PHP_EOL;
            }
            ?>

Solution

  • It looks like you just need to refresh the token prior to usage once it has been created by your user. The access_token only lasts for 30 minutes. You will need to refresh (and replace) it prior to each use. You are using the SDK though so that is easily supported.


    There is some example code in the readme to show you how to avoid the following error:

    https://github.com/XeroAPI/xero-php-oauth2#authorizedresourcephp

    The main piece is to ensure you are replacing the refreshed token set onto the api client prior to making your call. Are you sure it is being set correctly back on the config and then the accounting client?

    $config = XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken((string)$storage->getSession()['token']);