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
- 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
AccountingApi
class 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-id
accessToken
XeroConfiguration xconfig = new XeroConfiguration();
xconfig.ClientId = "yourClientId";
xconfig.ClientSecret = "yourClientSecret";
xconfig.CallbackUri = new Uri("https://localhost:5001"); //default for standard webapi template
xconfig.Scope = "openid profile email offline_access files accounting.transactions accounting.contacts";
var client = new XeroClient(xconfig);
Build the login link and send the user through the authorization_code
flow (a .NET Core Mvc example):
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Xero.NetStandard.OAuth2.Client;
using Xero.NetStandard.OAuth2.Config;
using Xero.NetStandard.OAuth2.Token;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Xero.NetStandard.OAuth2.Models;
using System.Collections.Generic;
namespace XeroNetStandardApp.Controllers
{
public class XeroOauth2Controller : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IOptions<XeroConfiguration> XeroConfig;
public XeroOauth2Controller(IOptions<XeroConfiguration> config, ILogger<HomeController> logger)
{
_logger = logger;
this.XeroConfig = config;
}
public IActionResult Index()
{
XeroConfiguration xconfig = new XeroConfiguration();
xconfig.ClientId = "yourClientId";
xconfig.ClientSecret = "yourClientSecret";
xconfig.CallbackUri = new Uri("https://localhost:5001"); //default for standard webapi template
xconfig.Scope = "openid profile email offline_access files accounting.transactions accounting.contacts";
var client = new XeroClient(xconfig);
return Redirect(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
XeroConfiguration xconfig = new XeroConfiguration();
xconfig.ClientId = "yourClientId";
xconfig.ClientSecret = "yourClientSecret";
xconfig.CallbackUri = new Uri("https://localhost:5001") //default for standard webapi template
xconfig.Scope = "openid profile email files accounting.transactions accounting.contacts offline_access";
var client = new XeroClient(xconfig);
//before getting the access token please check that the state matches
await client.RequestAccessTokenAsync(code);
//from here you will need to access your Xero Tenants
List<Tenant> tenants = await client.GetConnections();
// you will now have the tenant id and access token
foreach (Tenant tenant in tenants)
{
// 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.AccessToken
xeroToken.RefreshToken
xeroToken.IdToken
xeroToken.TokenType
xeroToken.ExpiresAtUtc
A NOTE on Tokens
You will still need to save the
XeroToken
in 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 toRefreshAccessTokenAsync
on 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
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Xero.NetStandard.OAuth2.Client;
using Xero.NetStandard.OAuth2.Config;
using Xero.NetStandard.OAuth2.Token;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Xero.NetStandard.OAuth2.Models;
using System.Collections.Generic;
namespace XeroNetStandardApp.Controllers
{
public class XeroOauth2Controller : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IOptions<XeroConfiguration> XeroConfig;
public XeroOauth2Controller(IOptions<XeroConfiguration> config, ILogger<HomeController> logger)
{
_logger = logger;
this.XeroConfig = config;
}
public IActionResult Index()
{
XeroConfiguration xconfig = new XeroConfiguration();
xconfig.ClientId = "yourClientId";
xconfig.CallbackUri = new Uri("https://localhost:5001"); //default for standard webapi template
xconfig.Scope = "openid profile email offline_access files accounting.transactions accounting.contacts";
xconfig.State = "YOUR_STATE"
var client = new XeroClient(xconfig);
// generate a random codeVerifier
var validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._~";
Random random = new Random();
int charsLength = random.Next(43, 128);
char[] randomChars = new char[charsLength];
for (int i = 0; i < charsLength; i++)
{
randomChars[i] = validChars[random.Next(0, validChars.Length)];
}
string codeVerifier = new String(randomChars);
return Redirect(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.
XeroConfiguration xconfig = new XeroConfiguration();
xconfig.ClientId = "yourClientId";
xconfig.CallbackUri = new Uri("https://localhost:5001") //default for standard webapi template
xconfig.Scope = "openid profile email files accounting.transactions accounting.contacts offline_access";
var client = new XeroClient(xconfig);
string codeVerifier = "Aaaaaaaaaa.Bbbbbbbbbb.0000000000.1111111111";
await client.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
using System;
using Xero.NetStandard.OAuth2.Api;
using Xero.NetStandard.OAuth2.Client;
using Xero.NetStandard.OAuth2.Config;
using System.Threading.Tasks;
namespace AsyncMain
{
class Program
{
static async Task Main(string[] args)
{
DotNetEnv.Env.Load();
var helloWorld = await GetHelloWorldAsync();
Console.WriteLine(helloWorld);
}
static async Task<string> GetHelloWorldAsync()
{
XeroConfiguration XeroConfig = new XeroConfiguration
{
ClientId = System.Environment.GetEnvironmentVariable("CLIENT_ID"),
ClientSecret = System.Environment.GetEnvironmentVariable("CLIENT_SECRET")
};
var client = new XeroClient(XeroConfig);
var xeroToken = await client.RequestClientCredentialsTokenAsync();
try {
var apiInstance = new AccountingApi();
var ifModifiedSince = DateTime.Parse("2000-02-06T12:17:43.202-08:00");
var where = "Status==\"ACTIVE\"";
var xeroTenantId = "";
var result = await apiInstance.GetAccountsAsync(xeroToken.AccessToken, xeroTenantId, ifModifiedSince, where, null);
return result.ToJson();
}
catch (Exception e)
{
Console.WriteLine("Exception when calling apiInstance.GetInvoice: " + e.Message );
return e.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
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DotNetEnv" Version="2.1.1" />
<PackageReference Include="IdentityModel" Version="4.0.0" />
<PackageReference Include="Xero.NetStandard.OAuth2" Version="3.19.0" />
<PackageReference Include="Xero.NetStandard.OAuth2Client" Version="1.5.0" />
</ItemGroup>
</Project>
Program.cs
using System;
using Xero.NetStandard.OAuth2.Api;
using Xero.NetStandard.OAuth2.Client;
using Xero.NetStandard.OAuth2.Config;
using System.Threading.Tasks;
namespace AsyncMain
{
class Program
{
static async Task Main(string[] args)
{
DotNetEnv.Env.Load();
var helloWorld = await GetHelloWorldAsync();
Console.WriteLine(helloWorld);
}
static async Task<string> GetHelloWorldAsync()
{
XeroConfiguration XeroConfig = new XeroConfiguration
{
ClientId = System.Environment.GetEnvironmentVariable("APPSTORE_CLIENT_ID"),
ClientSecret = System.Environment.GetEnvironmentVariable("APPSTORE_CLIENT_SECRET")
};
var client = new XeroClient(XeroConfig);
var xeroToken = await client.RequestClientCredentialsTokenAsync(false);
Guid subscriptionId = Guid.Parse("03bc74f2-1237-4477-b782-2dfb1a6d8b21");
try {
var apiInstance = new AppStoreApi();
var result = await apiInstance.GetSubscriptionAsync(xeroToken.AccessToken, subscriptionId);
return result.ToJson();
}
catch (Exception e)
{
Console.WriteLine("Exception when calling apiInstance.GetSubscriptionAsync: " + e.Message );
return e.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:
var AccountingApi = new AccountingApi();
var AssetApi = new AssetApi();
var BankFeedsApi = new BankFeedsApi();
var FilesApi = new FilesApi();
var IdentityApi = new IdentityApi();
var PayrollAUApi = new PayrollAUApi();
var PayrollNZApi = new PayrollNZApi();
var PayrollUkApi = new PayrollUkApi();
var ProjectApi = new ProjectApi();
var AppStoreApi = new AppStoreApi();
A full list of the SDK client's methods:
XeroConfiguration xconfig = new XeroConfiguration();
xconfig.ClientId = "yourClientId";
xconfig.ClientSecret = "yourClientSecret";
xconfig.CallbackUri = new Uri("https://localhost:5001");
xconfig.Scope = "openid profile email offline_access files accounting.transactions ...etc";
var client = new XeroClient(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
var AccountingApi = new AccountingApi();
var response = await AccountingApi.GetInvoicesAsync(accessToken, xeroTenantId);
- Get invoices from the last 7 days:
var AccountingApi = new AccountingApi();
var sevenDaysAgo = DateTime.Now.AddDays(-7).ToString("yyyy, MM, dd");
var invoicesFilter = "Date >= DateTime(" + sevenDaysAgo + ")";
var response = await AccountingApi.GetInvoicesAsync(accessToken, xeroTenantId, null, invoicesFilter);
- Create an invoice (Accounting APIs):
var contact = new Contact();
contact.Name = "John Smith";
var line = new LineItem() {
Description = "A golf ball",
Quantity = float.Parse(LineQuantity),
UnitAmount = float.Parse(LineUnitAmount),
AccountCode = "200"
};
var lines = new List<LineItem>() {
line
};
var invoice = new Invoice() {
Type = Invoice.TypeEnum.ACCREC,
Contact = contact,
Date = DateTime.Today,
DueDate = DateTime.Today.AddDays(30),
LineItems = lines
};
var invoiceList = new List<Invoice>();
invoiceList.Add(invoice);
var invoices = new Invoices();
invoices._Invoices = invoiceList;
var AccountingApi = new AccountingApi();
var response = await AccountingApi.CreateInvoicesAsync(accessToken, xeroTenantId, invoices);
- Get All Fixed Assets:
var AssetApi = new AssetApi();
var response = await AssetApi.GetAssetsAsync(accessToken, xeroTenantId, AssetStatusQueryParam.DRAFT);
- Create a fixed asset:
var asset = new Asset() {
AssetName = "Office Computer",
AssetNumber = "FA-001"
};
var AssetApi = new AssetApi();
var response = await AssetApi.CreateAssetAsync(accessToken, xeroTenantId, asset);
- Get Employees:
var PayrollAUApi = new PayrollAUApi();
var response = await PayrollAUApi.GetEmployeesAsync(accessToken, xeroTenantId);
var employees = response._Employees;
- Create a Employee:
DateTime dob = DateTime.Today.AddYears(-20);
HomeAddress homeAddress = new HomeAddress() {
AddressLine1 = "6 MeatMe Street",
AddressLine2 = " ",
Region = State.VIC,
City = "Long Island",
PostalCode = "0000",
Country = "New York"
};
Employee employee = new Employee() {
FirstName = "Bob",
LastName = "Belcher",
DateOfBirth = dob,
HomeAddress = homeAddress
};
var employees = new List<Employee>() { employee };
var PayrollAUApi = new PayrollAUApi();
var response = await PayrollAUApi.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
var feedConnection = new FeedConnection{
AccountToken = accountToken,
AccountNumber = accountNumber,
AccountType = accountTypeEnum,
AccountName = accountName,
Currency = currencyCode,
Country = countryCode
};
List<FeedConnection> list = new List<FeedConnection>();
list.Add(feedConnection);
FeedConnections items = new FeedConnections{
Pagination = new Pagination(),
Items = list
};
var BankfeedsApi = new BankFeedsApi();
await BankfeedsApi.CreateFeedConnectionsAsync(accessToken, xeroTenantId, items);
- Get all bankfeed connections
var BankFeedsApi = new BankFeedsApi();
var response = await BankFeedsApi.GetFeedConnectionsAsync(accessToken, xeroTenantId);
var feedConnections = response.Items;
- Delete a bankfeed connection
Guid bankfeedConnectionIdGuid = Guid.Parse(bankfeedConnectionId);
List<FeedConnection> list = new List<FeedConnection>();
list.Add(
new FeedConnection {
Id = bankfeedConnectionIdGuid
}
);
var feedConnections = new FeedConnections{
Items = list
};
var BankFeedsApi = new BankFeedsApi();
await BankFeedsApi.DeleteFeedConnectionsAsync(accessToken, xeroTenantId, feedConnections);
- Create statements against a bankfeed connection (plase ensure your start balance, end balance and statement amounts are mathematically correct)
StartBalance startBalance = new StartBalance{
Amount = decimal.Parse(startBalanceAmount),
CreditDebitIndicator = startIndicatorEnum
};
StatementLine statementLine = new StatementLine{
PostedDate = DateTime.Today,
Description = "A bankfeed satemement description",
Amount = 10,
CreditDebitIndicator = startIndicatorEnum,
TransactionId = new Guid().ToString()
};
EndBalance endBalance = new EndBalance{
Amount = decimal.Parse(startBalanceAmount) + statementLine.Amount,
CreditDebitIndicator = startIndicatorEnum
};
List<StatementLine> statementLines = new List<StatementLine>();
statementLines.Add(statementLine);
var statement = new Statement{
FeedConnectionId = new Guid(feedConnectionId),
StartDate = DateTime.Today.AddDays(-20),
EndDate = DateTime.Today,
StartBalance = startBalance,
EndBalance = endBalance,
StatementLines = statementLines,
};
List<Statement> statementList = new List<Statement>();
statementList.Add(statement);
Statements statements = new Statements{
Pagination = new Pagination(),
Items = statementList
};
var BankfeedsApi = new BankFeedsApi();
await BankfeedsApi.CreateStatementsAsync(accessToken, xeroTenantId, statements);
- Get all statements from all bankfeed connections
var BankFeedsApi = new BankFeedsApi();
var response = await BankFeedsApi.GetStatementsAsync(accessToken, xeroTenantId);
For full documentation please refer to Xero Bankfeed API documentation.
- Upload a file:
var FilesApi = new FilesApi();
// Convet IFormFile to byte array
byte[] byteArray;
using (MemoryStream data = new MemoryStream())
{
file.CopyTo(data);
byteArray = data.ToArray();
}
// Upload file
var response = await FilesApi.UploadFileAsync(
accessToken,
xeroTenantId,
null,
byteArray,
file.FileName,
file.ContentType
);
- Get Files:
var FilesApi = new FilesApi();
var response = await FilesApi.GetFilesAsync(accessToken, xeroTenantId);
var filesItems = response.Items;
- Delete a File:
Guid fileIDGuid = Guid.Parse(fileID);
var filesApi = new FilesApi();
await filesApi.DeleteFileAsync(accessToken, xeroTenantId, fileIDGuid);
- Rename a File:
Guid fileIDGuid = Guid.Parse(fileID);
var filesApi = new FilesApi();
FileObject file = await filesApi.GetFileAsync(accessToken, xeroTenantId, fileIDGuid);
file.Name = newName;
var response = await filesApi.UpdateFileAsync(accessToken, xeroTenantId, fileIDGuid, file);
- Get Associations
var FilesApi = new FilesApi();
var response = await FilesApi.GetFileAssociationsAsync(accessToken, xeroTenantId, new Guid(fileId));
- Create an Association
var FilesApi = new FilesApi();
var fileIdGuid = new Guid(fileId);
var invoiceIdGuid = new Guid(invoiceId);
Enum.TryParse<ObjectType>(objectType, out var objectTypeEnum);
Association association = new Association{
FileId = fileIdGuid,
ObjectId = invoiceIdGuid,
ObjectType = objectTypeEnum,
ObjectGroup = ObjectGroup.Invoice
};
var response = await FilesApi.CreateFileAssociationAsync(accessToken, xeroTenantId, fileIdGuid, association);
- Delete an Association
var fileIdGuid = new Guid(fileId);
var objectIdGuid = new Guid(objectId);
var FilesApi = new FilesApi();
await FilesApi.DeleteFileAssociationAsync(accessToken, xeroTenantId, fileIdGuid, objectIdGuid);
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:
var clientState = TokenUtilities.GetCurrentState();
if (state != clientState) {
return Content("Cross site forgery attack detected!");
}
var client = new XeroClient(XeroConfig.Value);
var xeroToken = (XeroOAuth2Token)await client.RequestAccessTokenAsync(code);
var decodedIdToken = JwtUtils.decode(xeroToken.IdToken);
if ( !JwtUtils.validateIdToken(xeroToken.IdToken, XeroConfig.Value.ClientId) )
{
return Content("ID token is not valid");
}
if ( !JwtUtils.validateAccessToken(xeroToken.IdToken) )
{
return Content("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.