PHP code example of xeroapi / xero-php-oauth2

1. Go to this page and download the library: Download xeroapi/xero-php-oauth2 library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

xeroapi / xero-php-oauth2 example snippets



  ini_set('display_errors', 'On');
  ague\OAuth2\Client\Provider\GenericProvider([
    'clientId'                => '__CLIENT_ID__',   
    'clientSecret'            => '__CLIENT_SECRET__',
    'redirectUri'             => '__REDIRECT_URI__',
    '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'
  ]);

  // Scope defines the data your app has permission to access.
  // Learn more about scopes at https://developer.xero.com/documentation/oauth2/scopes
  $options = [
    'scope' => ['openid email profile offline_access accounting.settings accounting.transactions accounting.contacts accounting.journals.read accounting.reports.read accounting.attachments']
  ];

  // This returns the authorizeUrl with necessary parameters applied (e.g. state).
  $authorizationUrl = $provider->getAuthorizationUrl($options);

  // Save the state generated for you and store it to the session.
  // For security, on callback we compare the saved state with the one returned to ensure they match.
  $_SESSION['oauth2state'] = $provider->getState();

  // Redirect the user to the authorization URL.
  header('Location: ' . $authorizationUrl);
  exit();


  ini_set('display_errors', 'On');
  ge Classe uses sessions for storing token > extend to your DB of choice
  $storage = new StorageClass();  

  $provider = new \League\OAuth2\Client\Provider\GenericProvider([
    'clientId'                => '__CLIENT_ID__',   
    'clientSecret'            => '__CLIENT_SECRET__',
    'redirectUri'             => '__REDIRECT_URI__', 
    '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'
  ]);
   
  // If we don't have an authorization code then get one
  if (!isset($_GET['code'])) {
    echo "Something went wrong, no authorization code found";
    exit("Something went wrong, no authorization code found");

  // Check given state against previously stored one to mitigate CSRF attack
  } elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
    echo "Invalid State";
    unset($_SESSION['oauth2state']);
    exit('Invalid state');
  } else {
  
    try {
      // Try to get an access token using the authorization code grant.
      $accessToken = $provider->getAccessToken('authorization_code', [
        'code' => $_GET['code']
      ]);
           
      $config = XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken( (string)$accessToken->getToken() );
      $identityApi = new XeroAPI\XeroPHP\Api\IdentityApi(
        new GuzzleHttp\Client(),
        $config
      );
       
      $result = $identityApi->getConnections();

      // Save my tokens, expiration tenant_id
      $storage->setToken(
        $accessToken->getToken(),
        $accessToken->getExpires(),
        $result[0]->getTenantId(),  
        $accessToken->getRefreshToken(),
        $accessToken->getValues()["id_token"]
      );
   
      header('Location: ' . './authorizedResource.php');
      exit();
     
    } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
      echo "Callback failed";
      exit();
    }
  }


  ini_set('display_errors', 'On');
  his class to deserialize error caught
  use XeroAPI\XeroPHP\AccountingObjectSerializer;

  // Storage Classe uses sessions for storing token > extend to your DB of choice
  $storage = new StorageClass();
  $xeroTenantId = (string)$storage->getSession()['tenant_id'];

  if ($storage->getHasExpired()) {
    $provider = new \League\OAuth2\Client\Provider\GenericProvider([
      'clientId'                => '__CLIENT_ID__',
      'clientSecret'            => '__CLIENT_SECRET__',
      'redirectUri'             => 'http://localhost:8888/xero-php-oauth2-starter/callback.php',
      'urlAuthorize'            => 'https://login.xero.com/identity/connect/authorize',
      'urlAccessToken'          => 'https://identity.xero.com/connect/token',
      'urlResourceOwnerDetails' => 'https://identity.xero.com/resources'
    ]);

    $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"] );
  }

  $config = XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken( (string)$storage->getSession()['token'] );	
  
  $accountingApi = new XeroAPI\XeroPHP\Api\AccountingApi(
    new GuzzleHttp\Client(),
    $config
  );

  $assetApi = new XeroAPI\XeroPHP\Api\AssetApi(
    new GuzzleHttp\Client(),
    $config
  );  

  $identityApi = new XeroAPI\XeroPHP\Api\IdentityApi(
    new GuzzleHttp\Client(),
    $config
  );  

  $projectApi = new XeroAPI\XeroPHP\Api\ProjectApi(
    new GuzzleHttp\Client(),
    $config
  );  

  $message = "no API calls";
  if (isset($_GET['action'])) {
    if ($_GET["action"] == 1) {
      // Get Organisation details
      $apiResponse = $accountingApi->getOrganisations($xeroTenantId);
      $message = 'Organisation Name: ' . $apiResponse->getOrganisations()[0]->getName();
    } else if ($_GET["action"] == 2) {
      // Create Contact
      try {
        $person = new XeroAPI\XeroPHP\Models\Accounting\ContactPerson;
        $person->setFirstName("John")
                ->setLastName("Smith")
                ->setEmailAddress("[email protected]")
                ->setIncludeInEmails(true);

        $arr_persons = [];
        array_push($arr_persons, $person);

        $contact = new XeroAPI\XeroPHP\Models\Accounting\Contact;
        $contact->setName('FooBar')
                ->setFirstName("Foo")
                ->setLastName("Bar")
                ->setEmailAddress("[email protected]")
                ->setContactPersons($arr_persons);
        
        $arr_contacts = [];
        array_push($arr_contacts, $contact);
        $contacts = new XeroAPI\XeroPHP\Models\Accounting\Contacts;
        $contacts->setContacts($arr_contacts);

        $apiResponse = $accountingApi->createContacts($xeroTenantId,$contacts);
        $message = 'New Contact Name: ' . $apiResponse->getContacts()[0]->getName();
      } catch (\XeroAPI\XeroPHP\ApiException $e) {
        $error = AccountingObjectSerializer::deserialize(
          $e->getResponseBody(),
          '\XeroAPI\XeroPHP\Models\Accounting\Error',
          []
        );
        $message = "ApiException - " . $error->getElements()[0]["validation_errors"][0]["message"];
      }
    } else if ($_GET["action"] == 3) {
      $if_modified_since = new \DateTime("2019-01-02T19:20:30+01:00"); // \DateTime | Only records created or modified since this timestamp will be returned
      $if_modified_since = null;
      $where = 'Type=="ACCREC"'; // string
      $where = null;
      $order = null; // string
      $ids = null; // string[] | Filter by a comma-separated list of Invoice Ids.
      $invoice_numbers = null; // string[] |  Filter by a comma-separated list of Invoice Numbers.
      $contact_ids = null; // string[] | Filter by a comma-separated list of ContactIDs.
      $statuses = array("DRAFT", "SUBMITTED");;
      $page = 1; // int | e.g. page=1 – Up to 100 invoices will be returned in a single API call with line items
      $


class StorageClass
{
	function __construct() {
		if( !isset($_SESSION) ){
      $this->init_session();
    	}
   	}

   	public function init_session(){
    session_start();
	}

    public function getSession() {
    	return $_SESSION['oauth2'];
    }

 	public function startSession($token, $secret, $expires = null)
	{
    session_start();
	}

	public function setToken($token, $expires = null, $tenantId, $refreshToken, $idToken)
	{    
    $_SESSION['oauth2'] = [
      'token' => $token,
      'expires' => $expires,
      'tenant_id' => $tenantId,
      'refresh_token' => $refreshToken,
      'id_token' => $idToken
    ];
	}

	public function getToken()
	{
    //If it doesn't exist or is expired, return null
    if (empty($this->getSession())
      || ($_SESSION['oauth2']['expires'] !== null
      && $_SESSION['oauth2']['expires'] <= time())
    ) {
      return null;
    }
    return $this->getSession();
	}

	public function getAccessToken()
	{
    return $_SESSION['oauth2']['token'];
	}

	public function getRefreshToken()
	{
    return $_SESSION['oauth2']['refresh_token'];
	}

	public function getExpires()
	{
    return $_SESSION['oauth2']['expires'];
	}

	public function getXeroTenantId()
	{
    return $_SESSION['oauth2']['tenant_id'];
	}

	public function getIdToken()
	{
    return $_SESSION['oauth2']['id_token'];
	}

	public function getHasExpired()
	{
		if (!empty($this->getSession())) 
		{
			if(time() > $this->getExpires())
			{
				return true;
			} else {
				return false;
			}
		} else {
			return true;
		}
	}
}

  $provider = new \League\OAuth2\Client\Provider\GenericProvider([
    'clientId'                => '__CLIENT_ID__',
    'clientSecret'            => '__CLIENT_SECRET__',
    'redirectUri'             => '__REDIRECT_URI__ ',
    'urlAuthorize'            => 'https://login.xero.com/identity/connect/authorize',
    'urlAccessToken'          => 'https://identity.xero.com/connect/token',
    'urlResourceOwnerDetails' => 'https://identity.xero.com/resources'
  ]);

  try {
    // Try to get an access token using the client credentials grant.
    $accessToken = $provider->getAccessToken('client_credentials');
    echo($accessToken->getToken());
  } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
    // Failed to get the access token
    exit($e->getMessage());
  }

// => /post-purchase-url?subscriptionId=03bc74f2-1237-4477-b782-2dfb1a6d8b21

$provider = new \League\OAuth2\Client\Provider\GenericProvider([
  'clientId'                => '__CLIENT_ID__',
  'clientSecret'            => '__CLIENT_SECRET__',
  'urlAuthorize'            => 'https://login.xero.com/identity/connect/authorize',
  'urlAccessToken'          => 'https://identity.xero.com/connect/token',
  'urlResourceOwnerDetails' => 'https://identity.xero.com/resources'
]);

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

$accessToken = $provider->getAccessToken('client_credentials');

$apiResponse = $apiInstance->getSubscription($subscriptionId);

echo($apiResponse);


onfigure OAuth2 access token for authorization: OAuth2
$config = XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken( 'YOUR_ACCESS_TOKEN' );       

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

$account = new XeroAPI\XeroPHP\Models\Accounting\Account;
$account->setCode('123456');
$account->setName('FooBar');
$account->setType(XeroAPI\XeroPHP\Models\Accounting\AccountType::EXPENSE);
$account->setDescription('Hello World');

try {
  $result = $apiInstance->createAccount($xeroTenantId, $account);
} catch (Exception $e) {
  echo 'Exception when calling AccountingApi->createAccount: ', $e->getMessage(), PHP_EOL;
}


onfigure OAuth2 access token for authorization: OAuth2
$config = XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken( 'YOUR_ACCESS_TOKEN' );       

$apiInstance = new XeroAPI\XeroPHP\Api\AssetApi(
    new GuzzleHttp\Client(),
    $config
);
$xeroTenantId = "YOUR_XERO_TENANT_ID";
$status = ;
$page = 1;
$pageSize = 5;
$orderBy = "AssetName";
$sortDirection = "ASC";
$filterBy = "Company Car";

try {
  $result = $apiInstance->getAssets($xeroTenantId, $status, $page, $pageSize, $orderBy, $sortDirection, $filterBy);
} catch (Exception $e) {
  echo 'Exception when calling AssetApi->getAssets: ', $e->getMessage(), PHP_EOL;
}

return [
  AccountingObjectSerializer::deserialize($content, '\XeroAPI\XeroPHP\Models\Accounting\Organisations', []),
  $response->getStatusCode(),
  $response->getHeaders()
];

$apiResponse = $apiInstance->getInvoicesWithHttpInfo($xeroTenantId, $if_modified_since, $where, $order, $ids, $invoice_numbers, $contact_ids, $statuses, $page,$

  // DECODE & VERIFY ACCESS_TOKEN
  $accessToken = (string)$storage->getSession()['token'];
  $jwtAccessTokenClaims = new XeroAPI\XeroPHP\JWTClaims();
  $jwtAccessTokenClaims->decodeAccessToken($accessToken);

  echo($jwtAccessTokenClaims->getNbf());
  echo($jwtAccessTokenClaims->getExp());
  echo($jwtAccessTokenClaims->getIss());
  echo($jwtAccessTokenClaims->getAudValue());
  echo($jwtAccessTokenClaims->getClientId());
  echo($jwtAccessTokenClaims->getAuthTime());
  echo($jwtAccessTokenClaims->getXeroUserId());
  echo($jwtAccessTokenClaims->getGlobalSessionId());
  echo($jwtAccessTokenClaims->getJti());
  echo($jwtAccessTokenClaims->getAuthenticationEventId());
  // scopes are an array therfore we dump not echo them.
  var_dump($jwtAccessTokenClaims->getScope());
  
  //DECODE & VERIFY ID_TOKEN 
  $IdToken = (string)$storage->getSession()['id_token'];
  $jwtIdTokenClaims = new XeroAPI\XeroPHP\JWTClaims();
  $jwtIdTokenClaims->decodeIdToken($IdToken);

  // 13 Claims are available
  echo($jwtIdTokenClaims->getNbf());
  echo($jwtIdTokenClaims->getExp());
  echo($jwtIdTokenClaims->getIss());
  echo($jwtIdTokenClaims->getAudValue());
  echo($jwtIdTokenClaims->getIat());
  echo($jwtIdTokenClaims->getAtHash());
  echo($jwtIdTokenClaims->getSid());
  echo($jwtIdTokenClaims->getSub());
  echo($jwtIdTokenClaims->getAuthTime());
  echo($jwtIdTokenClaims->getPreferredUsername());
  echo($jwtIdTokenClaims->getEmail());
  echo($jwtIdTokenClaims->getGivenName());
  echo($jwtIdTokenClaims->getFamilyName());

//Get account by id
$result = $apiInstance->getAccount($xeroTenantId,$accountId); 	

// display formatted date
echo($result->getAccounts()[0]->getUpdatedDateUtcAsDate()->format('Y-m-d H:i:s') ):

// display string in MS .NET JSON format \/Date(1439434356790)\/
echo($result->getAccounts()[0]->getUpdatedDateUtc() ):

//When setting a date for accounting or AU Payroll, remember to use the correct method
// For example setStartDate has a 2nd  method with "AsDate" if you wish to pass a native date
// This converts the date object to MS DateFormat
$leaveapplication->setStartDateAsDate(new DateTime('2020-05-02'));

// You'll get an error from the AU Payroll API if you try setStartDate("2020-05-02")
// But if you want to pass in MS Dateformat, this string will work.
$leaveapplication->setStartDate("/Date(1547164800000+0000)/");

composer