Skip to content
Developerhome

Authentication for Native applications

  Less than to read

In order to obtain a Bearer Token from a Native application, you need to implement the Authorization Code OAuth 2.0 grant flow using Proof Key for Code Exchange (PKCE). The Proof Key for Code Exchange (PKCE) (defined in RFC 7636) is a technique used to mitigate attacks to the Authorization Code OAuth 2.0 grant flow.

With PKCE, the application creates, for every authorization request, a cryptographically random key called code_verifier and its transformed value called code_challenge, which is sent to Sage ID to get the authorization_code. When the application receives the authorization_code, it will send the code and the code_verifier to Sage ID token endpoint to exchange them for the requested tokens.

The flow follows these steps:

  1. Your application initiates the flow and redirects the user to Sage ID (specifically to the /authorize endpoint), sending the code_challenge and code_challenge_method parameters.
  2. Sage ID redirects the user to your application with an authorization_code in the querystring.
  3. Your application sends the authorization_code and code_verifier together with the redirect_uri and the client_id to Sage ID. This is done using the /oauth/token endpoint.
  4. Sage ID validates this information and returns an Access Token (and optionally a Refresh Token) to your application.
  5. Your application securely stores the refresh token using the features of the operating system, e.g. the Data Protection API (DPAPI) on a per-user basis.
  6. Then, your application can use the Access Token to call the Sage 200 API on behalf of the user.
  7. When the Access Token expires, your application can call the /oauth/token endpoint using the refresh_token grant type, and the refresh token string, to obtain a new Access Token.
  8. When the user logs out of your application, the client MUST delete the refresh token.

How to Implement it

In the next points, we will work through the steps needed in order to implement it: create a code verifier and a code challenge, get the user’s authorization, get a token and access the Sage 200 API using the token.

1. Create a Code Verifier

First, you need to generate and store a code_verifier.

function base64URLEncode(str) {
    return str.toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
}
var verifier = base64URLEncode(crypto.randomBytes(32));

2. Create a Code Challenge

Using the code_verifier, generate a code_challenge that will be sent in the authorization request.

You must hash this value and not send a plain-text string.

function sha256(buffer) {
    return crypto.createHash('sha256').update(buffer).digest();
}
var challenge = base64URLEncode(sha256(verifier));

3. Get the User’s Authorization

To begin an Authorization Code flow, your Native application should first send the user to the authorization URL, including the code_challenge and the method used to generate it:

<a href="https://id.sage.com/authorize?audience=861692d/sage200nc.sage.com/api&scope=openid email profile Sales:ReadWrite offline_access&response_type=code&client_id=YOUR_CLIENT_ID&code_challenge=CODE_CHALLENGE&code_challenge_method=S256&redirect_uri=https://id.sage.com/mobile">
  Sign In
</a>

4. Exchange the Authorization Code for an Access Token

Now that you have an Authorization Code, you must exchange it for an Access Token that can be used to call the Sage 200 API. Using the Authorization Code from the previous step, you will need to POST to the Token URL sending also the code_verifier:

var client = new RestClient("https://id.sage.com/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://id.sage.com/mobile\"}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);

The response contains access_token, refresh_token, id_token, and token_type values, for example:

{
  "access_token": "eyJz93a...k4laUWw",
  "refresh_token": "GEbRxBN...edjnXbL",
  "id_token": "eyJ0XAi...4faeEoQ",
  "token_type": "Bearer"
}

Note that refresh_token will only be present in the response if you included the offline_access scope.

5. Call the Sage 200 API

Once you have the access_token you can use it to make calls to the Sage 200 API, by passing it as a Bearer Token in the Authorization header of the HTTP request:

// Use the Access Token to make Sage 200 API calls
$('#get-appointments').click(function(e) {
  e.preventDefault();

  $.ajax({
    cache: false,
    url: "https://sage200.sage.es/api/sales/products",
    headers: { "Authorization": "Bearer " + access_token }
  });
});

6. Get a new Access Token

If you have a refresh_token, you can call the /oauth/token endpoint using the refresh_token grant type, and the refresh token string, to obtain a new Access Token.

var client = new RestClient("https://id.sage.com/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "x-www-form-urlencoded");
request.AddParameter("application/json", "grant_type=refresh_token&refresh_token=REFRESH_TOKEN&client_id=YOUR_CLIENT_ID", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);

The response contains access_token, expires_in, id_token, and token_type values.

How do I securely store refresh tokens in a Native application?

Refresh Tokens must be stored in a secure manner as they essentially represent the username and password of the user. If they are stolen, they can exchange by a third party to get new access tokens and then impersonate the user and also their machine.

Under Windows, it is best to use the DPAPI in user mode to store a randomly generated AES key. This key can then be used to encrypt a file containing the refresh token string. It is recommended that this file is stored in isolated storage, or other suitable location within in the user profile folder hierarchy. NTFS permissions can be set to protect the file further.

Security of refresh tokens is the responsibility of your Native application.