The Xero-NetStandard SDK makes it easy for developers to access Xero's APIs in their Csharp code, and build robust applications and software using small business & general ledger accounting data.
- API Client documentation
- Sample Applications
- Xero Account Requirements
- Installation
- Configuration
- Authentication
- Auth with PKCE
- Custom Connections
- App Store Subscriptions
- API Clients
- Helper Methods
- Usage Examples
- Running Test(s) in Local
- SDK conventions
- Contributing
This SDK supports full method coverage for the following Xero API sets:
| API Set | Description |
|---|---|
Accounting | The Accounting API exposes accounting functions of the main Xero application (most commonly used) |
| Assets | The Assets API exposes fixed asset related functions of the Xero Accounting application |
| Files | The Files API provides access to the files, folders, and the association of files within a Xero organisation |
| Projects | Xero Projects allows businesses to track time and costs on projects/jobs and report on profitability |
| Payroll (AU) | The (AU) Payroll API exposes payroll related functions of the payroll Xero application |
| Payroll (UK) | The (UK) Payroll API exposes payroll related functions of the payroll Xero application |
| Payroll (NZ) | The (NZ) Payroll API exposes payroll related functions of the payroll Xero application |
| Bankfeeds | The Bankfeeds API facilitates the flow of transaction and statement data |
| AppStore | The AppStore API encapsulates subscription based endpoints |
Sample apps can get you started quickly with simple auth flows to advanced usage.
| Sample App | Description | Screenshot |
|---|---|---|
xero-netstandard-oauth2-app | This is a companion app built with .NET Core 3.1 MVC to demonstrate Xero OAuth 2.0 Client Authentication & OAuth 2.0 APIs. | ![]() |
xero-netstandard-oauth2-starter-dotnet-core | This is a starter app build with .NET Core 3.1 MVC to demonstrate Xero OAuth 2.0 Client Authentication & OAuth 2.0 APIs. | ![]() |
xero-netstandard-oauth2-blazor-pkce | This project is a Blazor WebAssembly Demo Application demonstrating the use of the Xero Files API, using the Xero NetStandard SDK to upload and delete files, folders and associations. | ![]() |
Xero-NetStandard-custom-connections-starter | A getting started command line app showing Custom Connections (aka client_credentials auth) a Xero premium option for building M2M integrations to a single org | ![]() |
xeropracticemanager-dotnetcore-oauth2-sample | This is an example dotnet core MVC application making use of Xero sign in, and Xero Practice Manager API access using OAuth2.0. | ![]() |
Xero-NetStandard-Webhooks-Receiver | This application demonstrates how to receive webhooks from Xero. | ![]() |
- Create a free Xero user account
- Login to your Xero developer dashboard and create an API application
- Copy the credentials from your API app and store them using a secure ENV variable strategy
- Decide the neccesary scopes for your app's functionality
This project is broken into 2 Nuget packages.
Xero.NetStandard.OAuth2 contains code to call all the XeroAPI endpoints
Xero.NetStandard.OAuth2Client code to authenticate and manage tokens
Use Nuget to download the packages via command line:
dotnet add package Xero.NetStandard.OAuth2
dotnet add package Xero.NetStandard.OAuth2Client
Or use the Package Manager Console inside Visual Studio
Install-Package Xero.NetStandard.OAuth2
Install-Package Xero.NetStandard.OAuth2Client
You can also download the source code from https://github.com/XeroAPI/Xero-NetStandard and compile it by yourself.
To get started there are a couple main classes:
- The
AccountingApiclass XeroOAuth2
The AccountingApi class is not coupled to the OAuth2 class so you easily can use another OAuth2 auth flow if you prefer.
To get started you will just need two things to make calls to the Accounting Api.
xero-tenant-idaccessToken
XeroConfigurationxconfig=newXeroConfiguration();xconfig.ClientId="yourClientId";xconfig.ClientSecret="yourClientSecret";xconfig.CallbackUri=newUri("https://localhost:5001");//default for standard webapi templatexconfig.Scope="openid profile email offline_access files accounting.transactions accounting.contacts";varclient=newXeroClient(xconfig);Build the login link and send the user through the authorization_code flow (a .NET Core Mvc example):
usingMicrosoft.AspNetCore.Mvc;usingMicrosoft.Extensions.Logging;usingXero.NetStandard.OAuth2.Client;usingXero.NetStandard.OAuth2.Config;usingXero.NetStandard.OAuth2.Token;usingSystem;usingSystem.Net.Http;usingSystem.Threading.Tasks;usingXero.NetStandard.OAuth2.Models;usingSystem.Collections.Generic;namespaceXeroNetStandardApp.Controllers{publicclassXeroOauth2Controller:Controller{privatereadonlyILogger<HomeController>_logger;privatereadonlyIOptions<XeroConfiguration>XeroConfig;publicXeroOauth2Controller(IOptions<XeroConfiguration>config,ILogger<HomeController>logger){_logger=logger;this.XeroConfig=config;}publicIActionResultIndex(){XeroConfigurationxconfig=newXeroConfiguration();xconfig.ClientId="yourClientId";xconfig.ClientSecret="yourClientSecret";xconfig.CallbackUri=newUri("https://localhost:5001");//default for standard webapi templatexconfig.Scope="openid profile email offline_access files accounting.transactions accounting.contacts";varclient=newXeroClient(xconfig);returnRedirect(client.BuildLoginUri());}}}The user will be redirected to login, authorise access and get redirected back to your callback
In the callback URI, Xero will return a parameter code and state (if you passed any)
- code
- state
You can then exchange the temp code for a XeroToken
XeroConfigurationxconfig=newXeroConfiguration();xconfig.ClientId="yourClientId";xconfig.ClientSecret="yourClientSecret";xconfig.CallbackUri=newUri("https://localhost:5001")//default for standard webapi template
xconfig.Scope="openid profile email files accounting.transactions accounting.contacts offline_access";varclient=newXeroClient(xconfig);//before getting the access token please check that the state matchesawaitclient.RequestAccessTokenAsync(code);//from here you will need to access your Xero TenantsList<Tenant>tenants=awaitclient.GetConnections();// you will now have the tenant id and access tokenforeach(Tenanttenantintenants){// do something with your tenant and access token//client.AccessToken;//tenant.TenantId;}You can now interact with the OAuth2 token data which has been mapped from Xero's OAuth2 json response.
{
"id_token": "xxx.yyy.zz",
"access_token": "xxx.yyy.zzz",
"expires_in": 1800,
"token_type": "Bearer",
"refresh_token": "xxxxxxxxx",
"scope": "email profile openid accounting.transactions offline_access"
}...to the XeroToken object model.
xeroToken.AccessTokenxeroToken.RefreshToken
xeroToken.IdToken
xeroToken.TokenType
xeroToken.ExpiresAtUtcA NOTE on Tokens
You will still need to save the
XeroTokenin your datastore to keep the connection alive until you or the user disconnect. If you have a valid XeroToken in your database you can restart a XeroAPI connection by passing the token toRefreshAccessTokenAsyncon an initializedclient.
First build the login link with the PKCE(Proof Key Code Exchange) flow (a .NET Core Mvc example).
PKCE is suited for mobile and desktop applications that don't have a way to keep the ClientSecret private
usingMicrosoft.AspNetCore.Mvc;usingMicrosoft.Extensions.Logging;usingXero.NetStandard.OAuth2.Client;usingXero.NetStandard.OAuth2.Config;usingXero.NetStandard.OAuth2.Token;usingSystem;usingSystem.Net.Http;usingSystem.Threading.Tasks;usingXero.NetStandard.OAuth2.Models;usingSystem.Collections.Generic;namespaceXeroNetStandardApp.Controllers{publicclassXeroOauth2Controller:Controller{privatereadonlyILogger<HomeController>_logger;privatereadonlyIOptions<XeroConfiguration>XeroConfig;publicXeroOauth2Controller(IOptions<XeroConfiguration>config,ILogger<HomeController>logger){_logger=logger;this.XeroConfig=config;}publicIActionResultIndex(){XeroConfigurationxconfig=newXeroConfiguration();xconfig.ClientId="yourClientId";xconfig.CallbackUri=newUri("https://localhost:5001");//default for standard webapi templatexconfig.Scope="openid profile email offline_access files accounting.transactions accounting.contacts";xconfig.State="YOUR_STATE"varclient=newXeroClient(xconfig);// generate a random codeVerifiervarvalidChars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._~";Randomrandom=newRandom();intcharsLength=random.Next(43,128);char[]randomChars=newchar[charsLength];for(inti=0;i<charsLength;i++){randomChars[i]=validChars[random.Next(0,validChars.Length)];}stringcodeVerifier=newString(randomChars);returnRedirect(client.BuildLoginUriPkce(codeVerifier));}}}The user will be redirected to login, authorise access and get redirected to your callback. You can then use the RequestAccessTokenPkceAsync to exchange for a XeroToken set.
XeroConfigurationxconfig=newXeroConfiguration();xconfig.ClientId="yourClientId";xconfig.CallbackUri=newUri("https://localhost:5001")//default for standard webapi template
xconfig.Scope="openid profile email files accounting.transactions accounting.contacts offline_access";varclient=newXeroClient(xconfig);stringcodeVerifier="Aaaaaaaaaa.Bbbbbbbbbb.0000000000.1111111111";awaitclient.RequestAccessTokenPkceAsync(code,codeVerifier);Custom Connections are a Xero premium option used for building M2M integrations to a single organisation. A custom connection uses OAuth2.0's client_credentials grant which eliminates the step of exchanging the temporary code for a token set.
To use this SDK with a Custom Connections var xeroTenantId = ""; must still be passed to work with a Custom Connection.
Full sample code: https://github.com/XeroAPI/Xero-NetStandard-custom-connections-starter
usingSystem;usingXero.NetStandard.OAuth2.Api;usingXero.NetStandard.OAuth2.Client;usingXero.NetStandard.OAuth2.Config;usingSystem.Threading.Tasks;namespaceAsyncMain{classProgram{staticasyncTaskMain(string[]args){DotNetEnv.Env.Load();varhelloWorld=awaitGetHelloWorldAsync();Console.WriteLine(helloWorld);}staticasyncTask<string>GetHelloWorldAsync(){XeroConfigurationXeroConfig=newXeroConfiguration{ClientId=System.Environment.GetEnvironmentVariable("CLIENT_ID"),ClientSecret=System.Environment.GetEnvironmentVariable("CLIENT_SECRET")};varclient=newXeroClient(XeroConfig);varxeroToken=awaitclient.RequestClientCredentialsTokenAsync();try{varapiInstance=newAccountingApi();varifModifiedSince=DateTime.Parse("2000-02-06T12:17:43.202-08:00");varwhere="Status==\"ACTIVE\"";varxeroTenantId="";varresult=awaitapiInstance.GetAccountsAsync(xeroToken.AccessToken,xeroTenantId,ifModifiedSince,where,null);returnresult.ToJson();}catch(Exceptione){Console.WriteLine("Exception when calling apiInstance.GetInvoice: "+e.Message);returne.ToString();}}}}Because Custom Connections are only valid for a single organisation you don't need an actual xero-tenant-id however the parameter remains and still requires an empty string.
If you are implementing subscriptions to participate in Xero's App Store you will need to setup App Store subscriptions endpoints. When a plan is successfully purchased, the user is redirected back to the URL specified in the setup process. The Xero App Store appends the subscription Id to this URL so you can immediately determine what plan the user has subscribed to through the subscriptions API. With your app credentials you can create a client via client_credentials grant type with the marketplace.billing scope. This unique access_token will allow you to query any functions in AppStoreApi. Client Credentials tokens to query app store endpoints will only work for apps that have completed the App Store on-boarding process.
=> /post-purchase-url?subscriptionId=03bc74f2-1237-4477-b782-2dfb1a6d8b21
csharp.csproj
<ProjectSdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReferenceInclude="DotNetEnv"Version="2.1.1" />
<PackageReferenceInclude="IdentityModel"Version="4.0.0" />
<PackageReferenceInclude="Xero.NetStandard.OAuth2"Version="3.19.0" />
<PackageReferenceInclude="Xero.NetStandard.OAuth2Client"Version="1.5.0" />
</ItemGroup>
</Project>Program.cs
usingSystem;usingXero.NetStandard.OAuth2.Api;usingXero.NetStandard.OAuth2.Client;usingXero.NetStandard.OAuth2.Config;usingSystem.Threading.Tasks;namespaceAsyncMain{classProgram{staticasyncTaskMain(string[]args){DotNetEnv.Env.Load();varhelloWorld=awaitGetHelloWorldAsync();Console.WriteLine(helloWorld);}staticasyncTask<string>GetHelloWorldAsync(){XeroConfigurationXeroConfig=newXeroConfiguration{ClientId=System.Environment.GetEnvironmentVariable("APPSTORE_CLIENT_ID"),ClientSecret=System.Environment.GetEnvironmentVariable("APPSTORE_CLIENT_SECRET")};varclient=newXeroClient(XeroConfig);varxeroToken=awaitclient.RequestClientCredentialsTokenAsync(false);GuidsubscriptionId=Guid.Parse("03bc74f2-1237-4477-b782-2dfb1a6d8b21");try{varapiInstance=newAppStoreApi();varresult=awaitapiInstance.GetSubscriptionAsync(xeroToken.AccessToken,subscriptionId);returnresult.ToJson();}catch(Exceptione){Console.WriteLine("Exception when calling apiInstance.GetSubscriptionAsync: "+e.Message);returne.ToString();}}}}// dotnet run
{
"currentPeriodEnd": "2021-09-02T14:08:58.772536Z",
"id": "03bc74f2-1237-4477-b782-2dfb1a6d8b21",
"organisationId": "79e8b2e5-c63d-4dce-888f-e0f3e9eac647",
"plans": [
{
"status": "ACTIVE",
"id": "6abc26f3-9390-4194-8b25-ce8b9942fda9",
"name": "Small",
"subscriptionItems": [
{
"id": "834cff4c-b753-4de2-9e7a-3451e14fa17a",
"price": {
"amount": 10.0000,
"currency": "NZD",
"id": "2310de92-c7c0-4bcb-b972-fb7612177bc7"
},
"product": {
"type": "FIXED",
"id": "9586421f-7325-4493-bac9-d93be06a6a38",
"name": ""
},
"startDate": "2021-08-02T14:08:58.772536Z",
"testMode": true
}
]
}
],
"startDate": "2021-08-02T14:08:58.772536Z",
"status": "ACTIVE",
"testMode": true
}You should use the subscription data to provision user access/permissions to your application.
In additon to a subscription Id being passed through the URL, when a purchase or an upgrade takes place you will be notified via a webhook. You can then use the subscription Id in the webhook payload to query the AppStore endpoints and determine what plan the user purchased, upgraded, downgraded or cancelled. Refer to Xero's documenation to learn more about setting up and receiving webhooks or review this blogpost explaing webhooks using this sdk.
https://developer.xero.com/documentation/guides/webhooks/overview/
You can access the different API sets and their available methods through the following:
varAccountingApi=newAccountingApi();varAssetApi=newAssetApi();varBankFeedsApi=newBankFeedsApi();varFilesApi=newFilesApi();varIdentityApi=newIdentityApi();varPayrollAUApi=newPayrollAUApi();varPayrollNZApi=newPayrollNZApi();varPayrollUkApi=newPayrollUkApi();varProjectApi=newProjectApi();varAppStoreApi=newAppStoreApi();A full list of the SDK client's methods:
XeroConfigurationxconfig=newXeroConfiguration();xconfig.ClientId="yourClientId";xconfig.ClientSecret="yourClientSecret";xconfig.CallbackUri=newUri("https://localhost:5001");xconfig.Scope="openid profile email offline_access files accounting.transactions ...etc";varclient=newXeroClient(xconfig);| Method | Description |
|---|---|
client.BuildLoginUri() | Returns a Xero authorize URI to start OAuth flow |
client.BuildLoginUri(string state, string scope) | Returns a Xero authorize URI (with state attached) to start OAuth flow |
client.BuildLoginUriPkce(string codeVerifier, string state, string scope) | Returns a Xero authorize URI to start OAuth flow with PKCE |
client.GetConnectionsAsync(IXeroToken xeroToken) | List of Tenants attached to accesstoken |
client.DeleteConnectionAsync(IXeroToken xeroToken, Tenant xeroTenant) | List of remaining Tenants attached to accesstoken |
client.RevokeAccessTokenAsync(IXeroToken xeroToken) | Revokes a IXeroToken and returns null |
client.RefreshAccessTokenAsync(IXeroToken xeroToken) | Returns a IXeroToken |
client.RequestClientCredentialsTokenAsync(Boolean fetchTenants=true) | Returns a IXeroToken, and defaults to calling GetConnections unless specified |
client.RequestAccessTokenAsync(string code) | Returns a IXeroToken |
client.RequestAccessTokenPkceAsync(string code, string codeVerifier) | Returns a IXeroToken |
client.GetCurrentValidTokenAsync(IXeroToken xeroToken) | Returns a IXeroToken |
- Call the refresh (shared between code & PKCE flows)
client.RefreshTokenAsync(xeroToken);- Get All invoices
varAccountingApi=newAccountingApi();varresponse=awaitAccountingApi.GetInvoicesAsync(accessToken,xeroTenantId);- Get invoices from the last 7 days:
varAccountingApi=newAccountingApi();varsevenDaysAgo=DateTime.Now.AddDays(-7).ToString("yyyy, MM, dd");varinvoicesFilter="Date >= DateTime("+sevenDaysAgo+")";varresponse=awaitAccountingApi.GetInvoicesAsync(accessToken,xeroTenantId,null,invoicesFilter);- Create an invoice (Accounting APIs):
varcontact=newContact();contact.Name="John Smith";varline=newLineItem(){Description="A golf ball",Quantity=float.Parse(LineQuantity),UnitAmount=float.Parse(LineUnitAmount),AccountCode="200"};varlines=newList<LineItem>(){line};varinvoice=newInvoice(){Type=Invoice.TypeEnum.ACCREC,Contact=contact,Date=DateTime.Today,DueDate=DateTime.Today.AddDays(30),LineItems=lines};varinvoiceList=newList<Invoice>();invoiceList.Add(invoice);varinvoices=newInvoices();invoices._Invoices=invoiceList;varAccountingApi=newAccountingApi();varresponse=awaitAccountingApi.CreateInvoicesAsync(accessToken,xeroTenantId,invoices);- Get All Fixed Assets:
varAssetApi=newAssetApi();varresponse=awaitAssetApi.GetAssetsAsync(accessToken,xeroTenantId,AssetStatusQueryParam.DRAFT);- Create a fixed asset:
varasset=newAsset(){AssetName="Office Computer",AssetNumber="FA-001"};varAssetApi=newAssetApi();varresponse=awaitAssetApi.CreateAssetAsync(accessToken,xeroTenantId,asset);- Get Employees:
varPayrollAUApi=newPayrollAUApi();varresponse=awaitPayrollAUApi.GetEmployeesAsync(accessToken,xeroTenantId);varemployees=response._Employees;- Create a Employee:
DateTimedob=DateTime.Today.AddYears(-20);HomeAddresshomeAddress=newHomeAddress(){AddressLine1="6 MeatMe Street",AddressLine2=" ",Region=State.VIC,City="Long Island",PostalCode="0000",Country="New York"};Employeeemployee=newEmployee(){FirstName="Bob",LastName="Belcher",DateOfBirth=dob,HomeAddress=homeAddress};varemployees=newList<Employee>(){employee};varPayrollAUApi=newPayrollAUApi();varresponse=awaitPayrollAUApi.CreateEmployeeAsync(accessToken,xeroTenantId,employees);Before trying the APIs, please make sure your company had been approved for Bankfeed endpoints and have the bankfeed scope enabled on your Xero OAuth 2.0 app. If you intend to become a Xero bankfeed partner please start by registering here.
- Create a bankfeed connection
varfeedConnection=newFeedConnection{AccountToken=accountToken,AccountNumber=accountNumber,AccountType=accountTypeEnum,AccountName=accountName,Currency=currencyCode,Country=countryCode};List<FeedConnection>list=newList<FeedConnection>();list.Add(feedConnection);FeedConnectionsitems=newFeedConnections{Pagination=newPagination(),Items=list};varBankfeedsApi=newBankFeedsApi();awaitBankfeedsApi.CreateFeedConnectionsAsync(accessToken,xeroTenantId,items);- Get all bankfeed connections
varBankFeedsApi=newBankFeedsApi();varresponse=awaitBankFeedsApi.GetFeedConnectionsAsync(accessToken,xeroTenantId);varfeedConnections=response.Items;- Delete a bankfeed connection
GuidbankfeedConnectionIdGuid=Guid.Parse(bankfeedConnectionId);List<FeedConnection>list=newList<FeedConnection>();list.Add(newFeedConnection{Id=bankfeedConnectionIdGuid});varfeedConnections=newFeedConnections{Items=list};varBankFeedsApi=newBankFeedsApi();awaitBankFeedsApi.DeleteFeedConnectionsAsync(accessToken,xeroTenantId,feedConnections);- Create statements against a bankfeed connection (plase ensure your start balance, end balance and statement amounts are mathematically correct)
StartBalancestartBalance=newStartBalance{Amount=decimal.Parse(startBalanceAmount),CreditDebitIndicator=startIndicatorEnum};StatementLinestatementLine=newStatementLine{PostedDate=DateTime.Today,Description="A bankfeed satemement description",Amount=10,CreditDebitIndicator=startIndicatorEnum,TransactionId=newGuid().ToString()};EndBalanceendBalance=newEndBalance{Amount=decimal.Parse(startBalanceAmount)+statementLine.Amount,CreditDebitIndicator=startIndicatorEnum};List<StatementLine>statementLines=newList<StatementLine>();statementLines.Add(statementLine);varstatement=newStatement{FeedConnectionId=newGuid(feedConnectionId),StartDate=DateTime.Today.AddDays(-20),EndDate=DateTime.Today,StartBalance=startBalance,EndBalance=endBalance,StatementLines=statementLines,};List<Statement>statementList=newList<Statement>();statementList.Add(statement);Statementsstatements=newStatements{Pagination=newPagination(),Items=statementList};varBankfeedsApi=newBankFeedsApi();awaitBankfeedsApi.CreateStatementsAsync(accessToken,xeroTenantId,statements);- Get all statements from all bankfeed connections
varBankFeedsApi=newBankFeedsApi();varresponse=awaitBankFeedsApi.GetStatementsAsync(accessToken,xeroTenantId);For full documentation please refer to Xero Bankfeed API documentation.
- Upload a file:
varFilesApi=newFilesApi();// Convet IFormFile to byte arraybyte[]byteArray;using(MemoryStreamdata=newMemoryStream()){file.CopyTo(data);byteArray=data.ToArray();}// Upload filevarresponse=awaitFilesApi.UploadFileAsync(accessToken,xeroTenantId,null,byteArray,file.FileName,file.ContentType);- Get Files:
varFilesApi=newFilesApi();varresponse=awaitFilesApi.GetFilesAsync(accessToken,xeroTenantId);varfilesItems=response.Items;- Delete a File:
GuidfileIDGuid=Guid.Parse(fileID);varfilesApi=newFilesApi();awaitfilesApi.DeleteFileAsync(accessToken,xeroTenantId,fileIDGuid);- Rename a File:
GuidfileIDGuid=Guid.Parse(fileID);varfilesApi=newFilesApi();FileObjectfile=awaitfilesApi.GetFileAsync(accessToken,xeroTenantId,fileIDGuid);file.Name=newName;varresponse=awaitfilesApi.UpdateFileAsync(accessToken,xeroTenantId,fileIDGuid,file);- Get Associations
varFilesApi=newFilesApi();varresponse=awaitFilesApi.GetFileAssociationsAsync(accessToken,xeroTenantId,newGuid(fileId));- Create an Association
varFilesApi=newFilesApi();varfileIdGuid=newGuid(fileId);varinvoiceIdGuid=newGuid(invoiceId);Enum.TryParse<ObjectType>(objectType,outvarobjectTypeEnum);Associationassociation=newAssociation{FileId=fileIdGuid,ObjectId=invoiceIdGuid,ObjectType=objectTypeEnum,ObjectGroup=ObjectGroup.Invoice};varresponse=awaitFilesApi.CreateFileAssociationAsync(accessToken,xeroTenantId,fileIdGuid,association);- Delete an Association
varfileIdGuid=newGuid(fileId);varobjectIdGuid=newGuid(objectId);varFilesApi=newFilesApi();awaitFilesApi.DeleteFileAssociationAsync(accessToken,xeroTenantId,fileIdGuid,objectIdGuid);For Running Test cases PRISM Mock Server needs to be started in the local machine. Steps to Run Test(s)
- Install PRISM from npm using the command: npm install -g @stoplight/prism-cli
- Verify Installation: prism --version
- Navigate to Xero-NetStandard--> Xero.NetStandard.OAuth2.Test--> util folder in the terminal
- Execute the script ./start-prism.sh
- This will start the PRISM Server in Local
- Run dotnet test to run the dotnet test cases.
Checking state in OAuth 2.0 flow can prevent CSFR attack. When acccess token and id token is returned, it is also security best practice to validate them.
Examples of checking state and jwt validation:
varclientState=TokenUtilities.GetCurrentState();if(state!=clientState){returnContent("Cross site forgery attack detected!");}varclient=newXeroClient(XeroConfig.Value);varxeroToken=(XeroOAuth2Token)awaitclient.RequestAccessTokenAsync(code);vardecodedIdToken=JwtUtils.decode(xeroToken.IdToken);if(!JwtUtils.validateIdToken(xeroToken.IdToken,XeroConfig.Value.ClientId)){returnContent("ID token is not valid");}if(!JwtUtils.validateAccessToken(xeroToken.IdToken)){returnContent("Access token is not valid");}As of June 30, 2018, Xero's API will remove support for TLS 1.0.
The easiest way to force TLS 1.2 is to set the Runtime Environment for your server (Tomcat, etc) to Java 1.8 which defaults to TLS 1.2.
This SDK is one of a number of SDK’s that the Xero Developer team builds and maintains. We are grateful for all the contributions that the community makes.
Here are a few things you should be aware of as a contributor:
- Xero has adopted the Contributor Covenant Code of Conduct, we expect all contributors in our community to adhere to it
- If you raise an issue then please make sure to fill out the github issue template, doing so helps us help you
- You’re welcome to raise PRs. As our SDKs are generated we may use your code in the core SDK build instead of merging your code directly.
- We have a contribution guide for you to follow when contributing to this SDK
- Curious about how we generate our SDK’s? Have a read of our process and have a look at our OpenAPISpec
- This software is published under the MIT License
For questions that aren’t related to SDKs please refer to our developer support page.






