9. Automatically creating third-party client applications

9.1. Introduction

CargoX Platform provides an /apps/ API endpoint to selected partners (referred to as Suppliers hereon) that have a need to create client applications for multiple integrations. An example would be an application which does not run in the cloud but needs to be installed on-premise. It makes sense for each such installation to have a separate client_id and client_secret. This endpoint is suitable for such specific cases.

Each supplier is issued an unique ID and a shared secret. The combination of both is used to requiest new OAuth credentials.

Warning

Please keep these credentials extremely safe. They should not be written down. Ideally, they should be baked into the application itself. If that's not possible and they need to be a part of configuration, make sure that the configuration is encrypted.

If these credentials are compromised an attacker may be able to gain access to all existing instances of your application. CargoX might not be able to detect or influence this.

If you are need to become a software supplier, contact our support at support@cargox.io.

9.2. Authorizing API requests: creating a hash

Each request to this API is authorized using your credentials. This is achieved by calculating a timestamped HMAC hash using your issued shared secret.

Message that uniquely defines a client application consists of three parts:

Parameter key

Parameter name

Description

app_id

Instance (Request) ID

The unique request ID. Every instance must use a different ID.

supplier_id

Supplier ID

Your supplier identification code, provided by CargoX.

timestamp

Unix timestamp

Current (Unix) time, truncated down to the last minute.

Attention

app_id (Application ID) is the unique ID of your request. CargoX will match the app_id and supplier_id in its database and issue only one set of client credentials per combination. This enabled you to call the endpoint multiple times (e.g. in case of network errors) and be certain you will always get the same result.

How you pick the app_id is up to you, just make sure they do not overlap. A good ID would be something that does not change -- e.g. you could either generate it on the first run and save it in the database, or use a combination of custom prefix and network card's MAC number.

The HMAC has needs to be calculated using the following formula:

HMAC('{app_id}-{supplier_id}-{timstamp}', '{supplier_secret}')

Here are a couple of examples of how to calculate the hash.

  • Python

    import time
    import hmac
    import hashlib
    
    APP_ID = get_application_id()
    SUPPLIER_ID = 'e225d965-205d-4187-b9bd-103f1a54c4d1'
    SECRET = '3c49474297c6338cce2788ec0ccee44fe38199bd74de3a03802404b2a7b62cfc'
    
    timestamp = int(time.time() // 60 * 60)
    message = '{app_id}-{supplier_id}-{timstamp}'.format(app_id=APP_ID,
                                                         supplier_id=SUPPLIER_ID,
                                                         timestamp=timestamp)
    hash = hmac.new(bytes.fromhex(SECRET), msg=message.encode('utf-8'), digestmod=hashlib.sha256).hexdigest()
    

  • PHP

    $APP_ID = get_application_id();
    $SUPPLIER_ID = 'e225d965-205d-4187-b9bd-103f1a54c4d1';
    $SECRET = '3c49474297c6338cce2788ec0ccee44fe38199bd74de3a03802404b2a7b62cfc';
    
    $timestamp = intval(intdiv(time(), 60) * 60);
    $message = sprintf('%s-%s-%d', $APP_ID, $SUPPLIER_ID, $timestamp);
    $hash = hash_hmac('sha256', $message, hex2bin($SECRET));
    

  • JavaScript

    // Define this somewhere within your app, as they do not change
    const app_id = get_application_id();
    const supplier_id = 'e225d965-205d-4187-b9bd-103f1a54c4d1';
    const secret = '3c49474297c6338cce2788ec0ccee44fe38199bd74de3a03802404b2a7b62cfc';
    
    let timestamp = Math.floor(Date.now() / 1000 / 60) * 60;
    // The following code uses CryptoJS: https://cryptojs.gitbook.io/docs/
    var hash = CryptoJS.HmacSHA256(`${app_id}-${supplier_id}-${timstamp}`, `${secret}`);
    var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
    

Important

To prevent replay attacks, the HMAC code includes the timestamp. This means that your request will not be valid indefinitely. More specifically, the server will accept only requests with a timestamp of current and previous minute (to prevent race conditions where the HMAC was generated just before the clock rolls around).

In general, this should be a safe margin. If you're running into issues where your hash code validation is faling, make sure you verify your clock is set up correctly first.

9.3. Create a client application

To create a new application, call the /apps endpoint with the following parameters:

Parameter key

Parameter name

Description

app_id

Instance (Request) ID

The unique request ID. Every instance must use a different ID.

supplier_id

Supplier ID

Your supplier identification code, provided by CargoX.

hash

HMAC-calculated hash

Unique hash calculated for this message.

email

Supplier's email

Email connected with this account. Must be unique for each instance.

Example: To create a new client application, send the following request:

curl --location --request POST 'https://cargox.digital/api/v3/apps/' \
--form 'app_id=supplier-D89FCA8719BDE9F18C' \
--form 'supplier_id=e225d965-205d-4187-b9bd-103f1a54c4d1' \
--form 'hash=4fef62145de199f3351f6f64f32234f6126d77d66f5614a9c5aa4cdf5f8dcdd9' \
--form '[email protected]'

The above request returns would OAuth credentials and application status as a JSON response:

{
    "client_id": "rP9wBF8zn8eipsDtYRM5JcnLOazTIl75JXswT20H",
    "client_secret": "6819upD3VqLLjvQLVCfTTDKqn4iYBtKdggGZ8km7PYHIWAtpSL0aHuIze3yWOOMBr1AjAdMgvsdoNeA0zgSBLHU2pbKVFkoGidj2x93rsDCWr3nqlgBBTpCEbVaYPaM9",
    "allowed_ip_ranges": "",
    "status": "active"
}

Note

As explained previously, subsequent requests with the same app_id and supplier_id will return existing credentials without creating a new application.

If your hash cannot be validated, you will get back a 403 FORBIDDEN error.

Depending on your agreement with CargoX, the credentials may be enabled automatically. If this is the case, status will display as "status": "active" and you can start using your newly assigned credentials straight away. If the credentials were issued but are not yet confirmed, the status will be shown as "status": "pending".

In case of pending credentials your application should regulary check in with CargoX (see the call bellow) and inquire about the status of credentials until they switch to active satte.

9.4. Fetch application OAuth credentials status

To fetch existing client application OAuth credentials, make the following request:

curl --location --request GET 'https://cargox.digital/api/v3/apps/supplier-D89FCA8719BDE9F18C/?supplier_id=e225d965-205d-4187-b9bd-103f1a54c4d1&hash=411b0dbf528c65219b92c350db9411651d2e5578a0185fc326dd9a09ab7ae487'

The above request returns OAuth credentials and application status as a JSON response:

{
    "client_id": "rP9wBF8zn8eipsDtYRM5JcnLOazTIl75JXswT20H",
    "client_secret": "6819upD3VqLLjvQLVCfTTDKqn4iYBtKdggGZ8km7PYHIWAtpSL0aHuIze3yWOOMBr1AjAdMgvsdoNeA0zgSBLHU2pbKVFkoGidj2x93rsDCWr3nqlgBBTpCEbVaYPaM9",
    "allowed_ip_ranges": "",
    "status": "active"
}