Authentication and OAuth 2.0

As a developer on the Crunch platform, you have programmatic access to clients’ data and resources, assuming they’ve authorised your application. To do this we provide an Oauth 2.0 implementation for authentication and authorisation, which is designed to allow your application to access the Crunch Accounting API whether the user is interacting with the application or not.

OAuth 2.0 is the industry-standard protocol for authorization. OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and living room devices. Source: https://oauth.net/2/

Note: By using the Crunch Accountancy API, you accept our Developer Terms of Service

1. Create Your application

To begin with you will need to obtain your Oauth 2 client credentials by creating a new application. While our API is in its initial beta phase we will onboard your new application to allow us to get a better understanding of how you plan to use the API. Please email api@crunch.co.uk with your name, company name, a brief overview of what you’ll be using the API for, whether it’s a confidential or a public type of application, and we will help you get setup straight away.

2. Obtain the access token

Before your application can access data using Crunch Accountancy API, it must obtain an access token that grants access to the API. The scope parameter used while requesting the access token controls the set of resources and operations that an access token permits. During the access-token request, your application sends one or more values in the scope parameter.

Obtaining the token requires an authentication step where the user logs in with their Crunch account. After logging in, the user is asked whether they are willing to grant the permissions that your application is requesting. This process is called user consent.

If the user grants the permission, the Crunch Oauth API sends your application an authorisation code at the redirect URL that you defined when setting up your application. This authorisation code can be exchanged to obtain the access token. If the user does not grant the permission, the server returns an error.

2.1: Prepare the authorisation request to obtain the authorisation code

The first step is to generate a URL with all the parameters to identify your application, and the permissions (scopes) that the user will be asked to grant when they authorise your application. When the URL is constructed you can redirect the user to that URL to allow them to authorise your application. The URL takes the following form:

GET https://oauth.crunch.co.uk/authorize

The following parameters are used with the authorize request:

Type Name Description Schema Default
Query client_id
required
The client identifier. string
Query redirect_uri
optional
The URL to which the browser will be redirected after authorization has been granted by the user. string
Query response_type
required
Use code for Authorization Code Grant Flow. string
Query scope
optional
The scopes your app needs to request authorization for. These must be separated by a space. See Scopes. string
Query state
recommended
An opaque value used by the client to maintain state between the request and callback. This value must be used by the application to prevent CSRF attacks. string
Query code_challenge
optional
Code challenge. REQUIRED if the type of the client app is public, when PKCE must be used. string
Query code_challenge_method
optional
Code verifier transformation method for PKCE. enum (S256, plain) plain

All query parameters must be URL encoded.

For example, for this set of parameters:

  • client_id: gf98we...78vyytc243
  • redirect_uri: https://my.app/integration/crunch
  • response_type: code
  • scope: all offline_access
  • state: k45$oi£j6#52=j

The resulting URL would look like:

https://oauth.crunch.co.uk/authorize?client_id=gf98we...78vyytc243&redirect_uri=https%3A%2F%2Fmy.app%2Fintegration%2Fcrunch&response_type=code&scope=all+offline_access&state=k45%24oi%A3j6%2352%3Dj

Please note that if your application is a public client, then the PKCE extension to the OAuth 2.0 flow must be used. Confidential clients can use PKCE optionally, for extra security.

Scopes

At the moment Crunch defines 2 possible scope values:

1. all

This is an all-encompassing scope, granting access to all the available Crunch resources. This can be narrowed down by using CRUD semantics, i.e. prefix the scope with either create, read, update or delete followed by a colon (:).

e.g. If your application only needs to create & read expenses, then you could use this scope value (unencoded for clarity): create:all read:all

The API Documentation specifies which scope is required for each individual endpoint under the Security group.

2. offline_access

Use offline_access in order to get a Refresh Token along with the Access Token. See Refreshing the access token for further details.

Authorisation response

Should the user authorise your application to access their Crunch account they will be redirected to the URL you specified in the redirect_uri URL parameter with the authorisation code as a code URL parameter:

https://my.app/integration/crunch&code=eyJz93a...k4laUWw&state=k45oi...j652j

The code you receive is a short-lived token and should be exchanged for an access token straight away.

2.2: Swap the code for an access token

The next step is to use the code to obtain an access token. The access token will allow you to access the Crunch API. The code exchange is performed via the /token endpoint:

POST https://oauth.crunch.co.uk/token

The /token endpoint takes the following request payload for the code exchange and should use the application/x-www-form-urlencoded content type (as supplied by the Content-Type http header):

Name Description Type
client_id
optional
The Client ID that was issued to the API User during signup.
Example : "gf98we...78vyytc243"
string
client_secret
optional
The Client Secret provided by the API User on signup.
Example : "something-gr33n"
string
code
required
The Authorization Code received from the initial /authorize call. Required when grant_type is authorization_code only.
Example : "4kjh234...cviu9ads"
string
grant_type
required
Denotes the flow you are using. For Authorization Code, use authorization_code.
Example : "authorization_code"
enum (authorization_code, refresh_token)
redirect_uri
optional
This is required only if it was set at the GET /authorize endpoint. The values must match.
Example : "https://my.app/integration/crunch"
string
code_verifier
optional
Code verifier. REQUIRED for public client apps, when PKCE must be used.
Example : "54i_ji...FDG~88"
string

Client authentication

Confidential clients must authenticate the request. The preferred way is via basic authentication, using the client_id & client_secret values as user & password, respectively. e.g. the header would look like:

Authorization: Basic <base64_encode(client_id:client_secret)>

If basic authentication is used, then the client_id & client_secret fields must not be passed in the payload! If basic authentication cannot be used for any reason, then authentication is performed via the form fields instead.

Public clients must use the client_id & code_verifier form fields.

Token response

The /token endpoint returns a JSON object that contains a new access token. The following snippet shows a sample response:

{
  "access_token": "22deaca1-d19a-4591-aaae-f20ccbc2bb65",
  "token_type": "Bearer",
  "expires_in": 172800,
  "refresh_token": "63d3e15c-9601-4dcf-99bc-aeea70fd1f1f",
  "scope": "all offline_access"
}

The access token response payload is described below:

Name Description Type
access_token
required
The access token issued by the authorization server.
Example : "eyJz93a...k4laUWw"
string
expires_in
optional
The lifetime in seconds of the access token.
Example : 86400
integer (int64)
refresh_token
optional
The refresh token, which can be used to obtain new access tokens using the same authorization grant. Issued only if the offline_access scope has been authorised.
Example : "GEbRxBN...edjnXbL"
string
scope
optional
The permissions granted by the User. Optional if identical to the scope requested by the client.
Example : "all offline_access"
string
token_type
required
The type of the token issued. Value is case insensitive. At this time, this field will always have the value Bearer.
Example : "Bearer"
string

3. Refreshing the access token

Access tokens are valid for a period of time, after which you need to get a new one using the latest refresh token returned to you from the previous request. You must write your code to anticipate the possibility that a granted access token might no longer work.

You only use the refresh token to obtain a new access token when the prior access token expires. Keep in mind that a refresh token is only for getting new (i.e., “refreshing”) access tokens; you can’t pass a refresh token when calling the Crunch API. You can refresh an access token without prompting the user for permission.

You refresh the access token by posting to the /token endpoint

POST https://oauth.crunch.co.uk/token

The /token endpoint takes the following request payload for access token refresh and should use the application/x-www-form-urlencoded content type (as supplied by the Content-Type http header):

Name Description Type
client_id
optional
The Client ID that was issued to the API User during signup.
Example : "gf98we...78vyytc243"
string
client_secret
optional
The Client Secret provided by the API User on signup.
Example : "something-gr33n"
string
grant_type
required
refresh_token enum (authorization_code, refresh_token)
refresh_token
required
The refresh token previously issued to the API User.
Example : "GEbRxBN...edjnXbL"
string
scope
optional
The scope of the access request. It MUST NOT include any scope not originally granted by the User, and if omitted it is treated as equal to the scope originally granted by the User.
Example : "all offline_access"
string

Client authentication

Confidential clients must authenticate in the same way as for the Access Token request.

Public clients must use the client_id form field only.

Refresh tokens must be stored securely since they allow a user to remain authenticated essentially forever. Especially important for public clients!

Token response

The /token endpoint returns a JSON object that contains a new access token. The following snippet shows a sample response:

{
  "access_token": "22deaca1-d19a-4591-aaae-f20ccbc2bb65",
  "token_type": "Bearer",
  "expires_in": 172800,
  "refresh_token": "63d3e15c-9601-4dcf-99bc-aeea70fd1f1f",
  "scope": "all offline_access"
}

The access token response payload is described below:

Name Description Type
access_token
required
The access token issued by the authorization server.
Example : "eyJz93a...k4laUWw"
string
expires_in
optional
The lifetime in seconds of the access token.
Example : 86400
integer (int64)
refresh_token
optional
The refresh token, which can be used to obtain new access tokens using the same authorization grant.
Example : "GEbRxBN...edjnXbL"
string
scope
optional
The permissions granted by the User. Optional if identical to the scope requested by the client.
Example : “all offline_access”
string
token_type
required
The type of the token issued. Value is case insensitive. At this time, this field will always have the value Bearer.
Example : "Bearer"
string

4. Accessing the Crunch API

Now you have a valid access token you can use this to access the Crunch resources. To do this you simply include the access token in the Authorization header with your API requests.

curl --location -g --request GET 'https://public-api.crunch.co.uk/v1/expenses' \
--header 'MediaType: application/json' \
--header 'Authorization: Bearer <access_token>'