User access tokens

Use your Service Account's Application ID and the AccessTokenList endpoint to create a user access token, which acts as the person who signed in to your application.

Introduction: when can I use a user access token?

As mentioned in previous articles, some integrations are not available through Service Accounts, and instead act as human accounts: a user access token can be generated and used instead. For a full overview of related scenarios, check Limitations of Service Accounts.

A user access token has to be created by making a POST request to the AccessTokenList endpoint.

Prerequisites

Before you start, you will need:

  • An application ID: you can get one by creating a Service Account as explained in the second step of How to create a Service Account.
  • The user's own IXON Cloud's email and password.
📘

Keep your credentials safe

Depending on how the API call is performed, make sure to protect your credentials.

How to create a user access token

To generate a user access token, follow these steps:

1. Build the Basic Auth credentials: the AccessTokenList call authenticates with Basic Auth using the end user's own IXON Cloud credentials — the email and password they enter in your application when they sign in. Your integration passes them straight through to this call; it doesn't need to store them.

The credential string is:

email:2fa:password

The 2fa field is only used if the account has Two-Factor Authentication enabled. Without 2FA, leave it empty. The string will contain two consecutive colons:

$(echo -n '[email protected]::Password1' | base64)

If you are using Postman: select Basic Auth as the Auth Type, then put {{email}}:{{2fa}} in the Username field and {{password}} in the Password field. Postman does the base64 encoding for you.

🚧

2FA codes are short-lived

A 2FA code is only valid for its own time window, so it cannot be used again in case the algorithm is called after the code has expired.

3. Call AccessTokenList with an expiry: a user access token is temporary, so the request body must include expiresIn, in seconds. You can choose anything between 60 seconds and 60 days.

curl --request POST \
     --url 'USER.URL/api/access-tokens?fields=secretId' \
     --header 'Api-Version: 2' \
     --header "Api-Application: $applicationId" \
     --header 'Content-Type: application/json' \
     --header "Authorization: Basic $base64_cipher_of_credentials" \
     --data '{"expiresIn": 3600}'

The ?fields=secretId query parameter trims the response down to just the token, if that's all you need.

The response contains the token in secretId, and its expiration date in expiresOn:

{
    "status": "success",
    "type": "AccessTokenCreateResponse",
    "data": {
        "publicId": "$responsePublicId",
        "expiresOn": "2021-02-02T00:59:59Z",
        "secretId": "$accessToken",
        "user": {
            "publicId": "$userPublicId",
            "name": "$username",
            "emailAddress": "$userEmailAddress",
            "support": false,
            "language": "en",
            "localisation": null,
            "timeZone": null,
            "registeredOn": "2020-09-01T10:59:29Z",
            "lastSeenOn": "2020-12-02T07:38:31Z",
            "termsOfUsePolicyAcceptedOn": "2020-09-01T10:59:29Z"
        }
    }
}

The user object in the response tells you which account the token acts as. This is useful to confirm who just signed in.

4. Use the user access token

Take secretId from the response and use it in the Authorization header. The header uses the standard HTTP Bearer scheme, so the word Bearer and a space precede the token:

Authorization: Bearer <secretId>

Note: use the secretId — not the publicId, which identifies the token record rather than being the secret itself.

Handling expiry

Because the token expires, your integration has to deal with renewal. Two workable patterns:

  • Refresh on schedule: read expiresOn from the response and request a new token before that timestamp passes.
  • Refresh on failure: catch the authentication failure, request a new token, and retry the original call once.

How to integrate the call into your code

This example shows how to implement the API call in a Python script.

1. Collect the credentials from the user: in a web application this is your sign-in form; from a script or CLI, prompt for them. Use getpass rather than input for the password so it doesn't appear on screen or in the shell history:

import getpass

email = input("IXON Cloud email: ")
password = getpass.getpass("Password: ")           # not echoed to the terminal
two_factor_code = input("2FA code (leave empty if not enabled): ")

2. Exchange them for a user access token: the token replaces the credentials from here on — you don't need to keep the password.

import base64
import requests

BASE_URL = "https://portal.ixon.cloud/api"
APPLICATION_ID = "7NWcb4adPRTK"          # your Service Account's Application ID


def sign_in(email, password, two_factor_code="", expires_in=3600):
    """Exchange a user's IXON Cloud credentials for a user access token."""
    credentials = f"{email}:{two_factor_code}:{password}"
    basic = base64.b64encode(credentials.encode()).decode()

    response = requests.post(
        f"{BASE_URL}/access-tokens",
        params={"fields": "secretId,expiresOn"},
        headers={
            "Api-Version": "2",
            "Api-Application": APPLICATION_ID,
            "Content-Type": "application/json",
            "Authorization": f"Basic {basic}",
        },
        json={"expiresIn": expires_in},
    )
    response.raise_for_status()

    data = response.json()["data"]
    return data["secretId"], data["expiresOn"]

3. Send the token on every subsequent call, alongside the same Application ID:

token, expires_on = sign_in(email, password, two_factor_code)

headers = {
    "Api-Version": "2",
    "Api-Application": APPLICATION_ID,
    "Authorization": f"Bearer {token}",
}

agents = requests.get(f"{BASE_URL}/agents", headers=headers).json()

4. Handle the token running out: check the stored expires_on before using the token, and send the user back through sign_in() when it has passed.

from datetime import datetime, timezone


def is_expired(expires_on):
    """expires_on is the ISO timestamp returned by sign_in()."""
    deadline = datetime.fromisoformat(expires_on.replace("Z", "+00:00"))
    return deadline <= datetime.now(timezone.utc)


if is_expired(expires_on):
    token, expires_on = sign_in(email, password, two_factor_code)
🚧

Keep the token server-side

A user access token grants that person's full access for as long as it lives. It is recommended to keep it in your server-side session store, not in the browser, and never put it in a URL or a log line.


Did this page help you?