To access the Commission’s application programming interface (API), your system must authenticate using the credentials we give you.
Authentication uses a bearer token that your application obtains using a client ID and a private key JWT (JSON Web Token) assertion.
On this page:
- How authentication works
- What you need
- Getting a bearer token
- Using the bearer token
- Who this applies to
How authentication works
Your system authenticates with the API using a private key JWT, instead of a shared client secret. At a high level, these are the steps:
- You generate a public and private key pair and give the public key to us when you register.
- To get a bearer token, your system creates a JWT assertion and signs it with your private key.
- You exchange the signed JWT for a bearer token.
- Your application includes the bearer token in the Authorization header of each API request.
Because you sign the JWT assertion with your private key, we can verify that the authentication request came from your organisation. You don’t need to send your private key or a shared secret across the network.
You can find out more about the JWT bearer standard in Request for Comments (RFC) 7523.
What you need
To authenticate with the API, you need:
- a client ID – we give you this when you register
- a public and a private key pair, and a self-signed certificate – your organisation generates and manages these. You need to:
- give us the public certificate during onboarding (getting started with the API)
- keep your private key secure and private (don’t share it)
- the ability to generate and sign a JWT client assertion using your private key. Your application uses this assertion when requesting an access token from the Commission's identity provider. A new assertion is generated when you get access tokens.
Here are some examples of ways to generate a sample public and private key pair. Replace the example variable names with values that suit your organisation, such as <provider-name>.
Generate a private key
Step 1. Generate the provider's private key
<code>
openssl genpkey \ -algorithm RSA \ -pkeyopt rsa_keygen_bits:2048 \ -out <provider-name>-acqsc-private-key.pem
</code>
Generate a self-signed public certificate
Step 2. Create the provider's public certificate
<code>
openssl req \ -new \ -x509 \ -sha256 \ -key <provider-name>-acqsc-private-key.pem \ -out <provider-name>-acqsc-certificate.pem \ -days 365 \ -subj "/O=<Provider Organisation Name>/CN=<Provider Name> - ACQSC Bulk API Client" \ -addext "basicConstraints=critical,CA:FALSE" \ -addext "keyUsage=critical,digitalSignature"
</code>
Step 3. Convert the public certificate to DER format for ACQSC
<code>
openssl x509 \ -in <provider-name>-acqsc-certificate.pem \ -outform DER \ -out <provider-name>-acqsc-certificate.cer
</code>
Note: The .cer file created in Step 3 is the public certificate that you give to the Commission during onboarding. The private key (<provider-name>-acqsc-private-key.pem) must stay securely within your organisation. You must never share it with the Commission or any other party. You can also keep the PEM certificate generated in Step 2 as part of your organisation’s key material.
Getting a bearer token
To access the API, your application must first get a bearer token from the Commission's identity provider.
Your application:
- creates a short-lived JWT client assertion
- signs it using your private key
- submits the signed assertion to the Commission's token endpoint.
The short-lived JWT client assertion contains:
- a header – this identifies how the JWT was signed and the certificate or public key to use to verify it
- a payload or body – contains claims such as your Client ID, the intended token endpoint, issue and expiry times, and a unique JWT ID
- a digital signature – created using your private key.
Your application then Base64URL-encodes these 3 components and joins them with full stops (.) to produce the compact JWT string used in the token request:
<Base64URL-encoded header>.<Base64URL-encoded payload>.<Base64URL-encoded signature>
For example:
eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiJ9.eyJpc3MiOiI8Y2xpZW50LWlkPiIsLi4ufQ.<signature>
That complete string is supplied as the client_assertion=<signed-jwt-assertion> value in the OAuth token request.
The Commission's identity provider verifies the signature using the public certificate you supplied during onboarding. If the assertion is valid, the identity provider authenticates your application and issues a bearer token.
JWT client assertion example
The JWT header identifies the signing algorithm and the certificate associated with the private key:
<code>
{
"alg": "PS256",
"typ": "JWT",
"x5t#S256": "<certificate-sha256-thumbprint>"
}
</code>
Where:
- <certificate-sha256-thumbprint> is the Base64URL-encoded SHA-256 thumbprint of the public certificate registered with the Commission.
- PS256 is used to sign the assertion using your private key.
The JWT assertion contains:
<code>
{
"aud": "<token-endpoint>",
"iss": "<client-id>",
"sub": "<client-id>",
"iat": <current-unix-time>,
"nbf": <current-unix-time-minus-small-clock-skew>,
"exp": <assertion-expiry-unix-time>,
"jti": "<unique-jwt-id>"
}
</code>
Where:
<token-endpoint> is the token endpoint supplied by the Commission
<client-id> is the Client ID issued to your organisation by the Commission
<current-unix-time> is the current time expressed as Unix epoch seconds
<current-unix-time-minus-small-clock-skew> may be set slightly before the current time to allow for minor clock differences between systems
<unique-jwt-id> must be a new unique value for each assertion, such as a UUID
<assertion-expiry-unix-time> should be a short period after the assertion is created, ideally no more than 10 mins.
Once the signed client assertion has been created (base64, dot delimited string), submit it to the token endpoint using the OAuth 2.0 Client Credentials flow:
<code>
curl --location '<token-endpoint>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<client-id>' \
--data-urlencode 'scope=<api-scope>' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
--data-urlencode 'client_assertion=<signed-jwt-assertion>'
</code>
Where:
<client-id> is the Client ID issued by the Commission
<token-endpoint> is the token endpoint supplied by the Commission
<api-scope> is supplied by the Commission
<signed-jwt-assertion> is the JWT generated and signed using your private key.
A successful request returns an access token like:
<code>
{
"token_type": "Bearer",
"expires_in": "<token-lifetime-seconds>",
“access_token": “<bearer-token>”
}
</code>
The value of the "access_token" is the bearer token used to call the API. The Commission uses access tokens with a lifetime of no more than 10 minutes.
Using the bearer token
Include your bearer token in the Authorization header of every API request:
<code>
Authorization: Bearer <bearer-token>
</code>
For example:
<code>
curl --location '<bulk-api-endpoint>' \
--header 'Authorization: Bearer <bearer-token>' \
--header 'Content-Type: application/json'
</code>
Your application must get a new bearer token when the current token expires or is no longer suitable for use. You can reuse the token for multiple requests until it expires.
The API does not support refresh-token flow. To get another bearer token, your application:
- creates a new JWT client assertion
- generates a new unique jti
- signs the assertion using your private key
- sends the assertion to the <token-endpoint>
- receives a new bearer token.
Who this applies to
The authentication process applies to:
- registered providers getting a bearer token to call the API in the Production environment
- third-party software operators that need to show that their software can connect to Commission systems during Sandbox Verification Testing (SVT) before being authorised for production.
In some cases, your software may need to repeat conformance testing. For example, when:
- there's a significant update to the API
- there’s a significant change to your software.