Xero .NET Standard SDK

repository·master·Indexed 40 days ago

https://github.com/xeroapi/xero-netstandard

A C# SDK for accessing Xero API sets, including Accounting, Payroll, Files, and App Store. It provides full method coverage for interacting with the Xero ecosystem and includes support for OAuth 2.0 Authorization Code Flow, PKCE, and Machine-to-Machine (M2M) integrations via Custom Connections. The SDK is distributed via the Xero.NetStandard.OAuth2 and Xero.NetStandard.OAuth2Client NuGet packages.

Tokens
10.1K
Snippets
22
Records
23
Agent score
0%

What's inside Xero

  1. Manage XeroToken data

    master

    The XeroToken object maps the JSON response from Xero's OAuth2 endpoint. You should persist this token in your datastore to maintain the connection. To restore a connection using a stored token, pass it to RefreshAccessTokenAsync on an initialized XeroClient.

    // Properties available on the XeroToken object:
    xeroToken.AccessToken
    xeroToken.RefreshToken
    xeroToken.IdToken
    xeroToken.TokenType
    xeroToken.ExpiresAtUtc
    
    // To restart a connection using a stored token:
    // await client.RefreshAccessTokenAsync(storedToken);
  2. Authenticate using PKCE flow

    master

    The PKCE (Proof Key Code Exchange) flow is recommended for mobile and desktop applications that cannot securely store a ClientSecret.

    To implement this:

    1. Generate a random codeVerifier (a high-entropy cryptographic string).
    2. Use XeroClient.BuildLoginUriPkce(codeVerifier) to generate the authorization URL to redirect the user.
    3. After the user authorizes and is redirected back to your callback with a code, use XeroClient.RequestAccessTokenPkceAsync(code, codeVerifier) to exchange that code for a XeroToken set.
    // 1. Setup configuration
    XeroConfiguration xconfig = new XeroConfiguration();
    xconfig.ClientId = "yourClientId";
    xconfig.CallbackUri = new Uri("https://localhost:5001");
    xconfig.Scope = "openid profile email offline_access files accounting.transactions accounting.contacts";
    xconfig.State = "YOUR_STATE";
    
    var client = new XeroClient(xconfig);
    
    // 2. 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);
    
    // 3. Redirect user to login
    return Redirect(client.BuildLoginUriPkce(codeVerifier));
    
    // --- Later, in your callback controller ---
    
    // 4. Exchange code for token
    await client.RequestAccessTokenPkceAsync(code, codeVerifier);
  3. Use Custom Connections for M2M integrations

    master

    Custom Connections are a premium Xero feature for Machine-to-Machine (M2M) integrations targeting a single organization. This uses the client_credentials grant, which bypasses the manual authorization step.

    Important: Even though Custom Connections are valid for only one organization, you must still pass an empty string "" for the xeroTenantId parameter in API calls.

    XeroConfiguration XeroConfig = new XeroConfiguration
    {
        ClientId = System.Environment.GetEnvironmentVariable("CLIENT_ID"),
        ClientSecret = System.Environment.GetEnvironmentVariable("CLIENT_SECRET")
    };
    
    var client = new XeroClient(XeroConfig);
    // Request token using client credentials grant
    var xeroToken = await client.RequestClientCredentialsTokenAsync();
    
    try {
        var apiInstance = new AccountingApi();
        var xeroTenantId = ""; // Must be an empty string for Custom Connections
        var result = await apiInstance.GetAccountsAsync(xeroToken.AccessToken, xeroTenantId, null, null, null);
        return result.ToJson();
    }
    catch (Exception e) {
        // Handle error
    }
  4. Integrate with Xero App Store Subscriptions

    master

    To manage App Store subscriptions, use the AppStoreApi. When a user purchases a plan, Xero redirects them to your URL with a subscriptionId query parameter.

    To query subscription details:

    1. Create a XeroClient using your App Store credentials.
    2. Use RequestClientCredentialsTokenAsync(false) to get a token with the marketplace.billing scope.
    3. Call AppStoreApi.GetSubscriptionAsync(accessToken, subscriptionId) to retrieve the plan details.
    XeroConfiguration XeroConfig = new XeroConfiguration
    {
        ClientId = System.Environment.GetEnvironmentVariable("APPSTORE_CLIENT_ID"),
        ClientSecret = System.Environment.GetEnvironmentVariable("APPSTORE_CLIENT_SECRET")
    };
    
    var client = new XeroClient(XeroConfig);
    // Note: passing false to avoid fetching tenants if not needed
    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);
        Console.WriteLine(result.ToJson());
    }
    catch (Exception e) {
        Console.WriteLine(e.Message);
    }
  5. Run local tests using PRISM Mock Server

    master

    To run local test cases, you must start the PRISM Mock Server on your machine.

    1. Install PRISM globally via npm: npm install -g @stoplight/prism-cli.
    2. Verify installation with prism --version.
    3. Navigate to the Xero-NetStandard--> Xero.NetStandard.OAuth2.Test--> util folder in your terminal.
    4. Execute the startup script: ./start-prism.sh.
    5. Once the server is running, execute dotnet test to run the test cases.
    npm install -g @stoplight/prism-cli
    prism --version
    # Navigate to Xero-NetStandard--> Xero.NetStandard.OAuth2.Test--> util
    ./start-prism.sh
    dotnet test
  6. Implement OAuth 2.0 security checks

    master

    To prevent CSRF attacks and ensure token integrity, follow these security best practices:

    1. State Check: Compare the state returned in the OAuth flow with the state stored locally using TokenUtilities.GetCurrentState(). If they do not match, a CSRF attack may be in progress.
    2. JWT Validation: After receiving the access token and ID token, validate the ID token using JwtUtils.validateIdToken (passing your ClientId) and validate the access token using JwtUtils.validateAccessToken.
    // State check
    var clientState = TokenUtilities.GetCurrentState();
    if (state != clientState) {
      return Content("Cross site forgery attack detected!");
    }
    
    // Token validation
    var client = new XeroClient(XeroConfig.Value);
    var xeroToken = (XeroOAuth2Token)await client.RequestAccessTokenAsync(code);
    
    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");
    }
  7. Install Xero-NetStandard via NuGet

    master

    The SDK is split into two NuGet packages. You should install both to handle both API calls and OAuth2 authentication/token management.

    • Xero.NetStandard.OAuth2: Contains code to call all XeroAPI endpoints.
    • Xero.NetStandard.OAuth2Client: Contains code to authenticate and manage tokens.
    dotnet add package Xero.NetStandard.OAuth2
    dotnet add package Xero.NetStandard.OAuth2Client

    Or using Package Manager Console in Visual Studio

    Install-Package Xero.NetStandard.OAuth2
    Install-Package Xero.NetStandard.OAuth2Client
  8. Implement Xero OAuth 2.0 Authorization Code Flow

    master

    The standard authentication flow involves two steps: redirecting the user to Xero to authorize your app, and then exchanging the returned code for an access token and tenant information.

    // Step 1: Build the login link and redirect the user
    public IActionResult Index()
    {
        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 accounting.contacts";
    
        var client = new XeroClient(xconfig);
        return Redirect(client.BuildLoginUri());
    }
    
    // Step 2: In your callback URI, exchange the 'code' for tokens and tenants
    public async Task<IActionResult> Callback(string code)
    {
        XeroConfiguration xconfig = new XeroConfiguration(); 
        xconfig.ClientId = "yourClientId";
        xconfig.ClientSecret = "yourClientSecret";
        xconfig.CallbackUri = new Uri("https://localhost:5001");
        xconfig.Scope = "openid profile email files accounting.transactions accounting.contacts offline_access";
        
        var client = new XeroClient(xconfig);
        
        // Exchange the temporary code for a XeroToken
        await client.RequestAccessTokenAsync(code);
        
        // Retrieve the connected Xero Tenants
        List<Tenant> tenants = await client.GetConnections();
        
        foreach (Tenant tenant in tenants)
        {
            // Use tenant.TenantId and client.AccessToken to make API calls
        }
        return Ok();
    }
  9. Create a Xero App

    master

    To use the SDK, you must first register an application in the Xero developer portal:

    1. Create a free Xero user account.
    2. Navigate to the Xero OAuth2 creation URL.
    3. Click the "or Try oAuth2" link.
    4. Enter your App name, company URL, privacy policy URL, and Redirect URI (the callback URL, e.g., https://localhost:5001).
    5. Agree to terms and click "Create App".
    6. Click "Generate a secret".
    7. Copy and save your Client ID and Client Secret.
    8. Click "Save".
  10. Configure XeroClient with XeroConfiguration

    master

    To initialize a XeroClient, you must provide a XeroConfiguration object containing your application credentials and requested scopes.

    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);
  11. Exchange Authorization Code for Access Token and Tenants

    master

    After the user is redirected back to your CallbackUri, you will receive a code and a state parameter. Use RequestAccessTokenAsync to exchange the code for an access token, then call GetConnections() to retrieve the available Xero Tenant objects.

    XeroConfiguration xeroConfig = new XeroConfiguration(); 
        xeroConfig.ClientId = "yourClientId";
        xeroConfig.ClientSecret = "yourClientSecret";
        xeroConfig.CallbackUri = new Uri("https://localhost:5001");
        xeroConfig.Scope = "openid profile email files accounting.transactions accounting.contacts offline_access";
        var client = new XeroClient(xeroConfig);
    
        // Exchange the code for an access token (ensure state matches your original request)
        await client.RequestAccessTokenAsync(code, "yourState");
    
        // Retrieve the Xero Tenants
        List<Tenant> tenants = await client.GetConnections();
    
        foreach (Tenant tenant in tenants)
        {
            // Access the token and tenant ID
            // string token = client.AccessToken;
            // string tenantId = tenant.TenantId;
        }