---
title: "Authorising an application or service to call the LUSID API"
slug: "authorising-an-application-or-service-to-call-the-lusid-api"
tags: ["access token", "client secret", "SDK", "API"]
updated: 2024-09-18T15:56:06Z
published: 2024-09-18T15:56:06Z
canonical: "support.lusid.com/authorising-an-application-or-service-to-call-the-lusid-api"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://support.lusid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authorising an application or service to call the LUSID API

In this tutorial we’ll see how to authorise calls to the LUSID API, both directly to the REST API and indirectly using the SDK.

Let’s imagine we want to create an application or service that retrieves instruments from the LUSID Security Master. To do this, we need to authorise a call to the LUSID [ListInstruments](https://www.lusid.com/docs/api/#operation/ListInstruments) API.

> **Note:** To complete this tutorial, you must yourself have suitable permissions. This can most easily be achieved by assigning your LUSID user the built-in `lusid-administrator` role. This should already be the case if you are the domain owner.

## Step 1: Setting up a service user account with appropriate permissions

There are two types of user in LUSID, [personal and service](/v1/docs/what-are-a-personal-user-and-a-service-user).

Whilst it is perfectly possible to use the credentials of a personal user to authorise calls to the LUSID API, we recommend using those of a service user instead, especially if you are creating an automated service. This is because the account is not tied to the email address of a person who might leave your organisation.

We recommend setting up one service user account per distinct application or service so that it only has permissions to perform the operations for which it is designed, and no more. In this tutorial we're going to use the [default roles and policies](/v1/docs/what-default-roles-and-policies-are-provided-with-lusid) provided with LUSID to grant access to the example data also provided with LUSID, but you can create your own policies if you wish.

1. Sign in to the [LUSID web app](https://www.lusid.com/app) using the credentials of a LUSID administrator.
2. From the left-hand menu, select **Identity and access > Users**: ![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/1faec969-caca-4ca8-b5f5-9fe681954fc8.png)
3. On the **Users** dashboard, click the **Create user** button: ![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/263f105e-7fa5-41af-99ac-b62cba4936d6.png)
4. Specify an **Account type** of `Service`, enter your **Email address** to become the service owner, specify a **Login** user name (this must look like an email address but no email will be sent to it) and click the **Add roles** button to assign the default `lusid-evaluator` role provided with LUSID: ![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/44da9b9f-ad40-4579-9b56-63665cae8f07.png)
5. Click the **Save** button to send yourself an email to complete the sign up process.
6. Follow the instructions in the email to verify the account and specify a [complex password](/v1/docs/how-do-i-set-up-a-service-user-account#completing-the-sign-up-process).

## Step 2: Generating a client ID and client secret

We now have a username and password for a verified LUSID service user.

In order to obtain an API access token, we also need a client ID and client secret. To generate these:

1. From the left-hand menu, select **Identity and access > Applications**.
2. On the **Applications** dashboard, click the **Create application** button: ![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/8c2f7dc9-3f50-48aa-9562-8910561c0da9.png)
3. Specify a **Client Id** (no spaces) and a **Display name**, and click the **Save** button. LUSID automatically generates a client secret.
4. On the **Applications** dashboard, click the ![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/5ed6069f-c7df-4453-8479-99a984ffcbfe.png) **View** icon for the row to reveal the client secret and Okta's dedicated token URL for your LUSID domain: ![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/7d9a4d24-d64d-4231-b89b-1f73de3fd331.png)

We now have:

- A username and password for a verified LUSID service user.
- A client ID and client secret.
- A dedicated Okta token URL.

The next step depends on what you want to do:

## Step 3: Explicitly obtaining an API access token and calling the REST API directly

> **Note:** This step assumes you have installed [curl](https://curl.se) (similar tools are available).

To call the LUSID REST API directly we must obtain an [API access token](/v1/docs/what-are-an-api-access-token-and-a-client-secret) and supply it as a Bearer token in the Authorization HTTP header:

1. Make a POST request to your dedicated Okta token URL, passing in the username, password, client ID and client secret, suitably encoded:

```powershell
curl -X POST <your-okta-token-url>
   -H "Content-Type: application/x-www-form-urlencoded; charset=ISO-8859-1"
   --data-urlencode grant_type="password"
   --data-urlencode username="<your-username>"
   --data-urlencode password="<your-password>"
   --data-urlencode scope="openid client groups"
   --data-urlencode client_id="<your-client-id>"
   --data-urlencode client_secret="<your-client-secret>"
```

The response from Okta contains 2 tokens (actual data shortened for brevity):

```json
{
   "token_type": "Bearer",
   "expires_in": 3600,
   "access_token": "eyJraWQiOiJvZDFzeFk4WTlPalMyZ2dZT3VidVBYT2dRX0dURkcwZ1...wmlxPjh49DYeEuh_w4vt2Q",
   "scope": client groups openid",
   "id_token": "eyJraWQiOiJvZDFzeFk4WTlPalMyZ2dZT3VidVBYT2dzeFk4WTlPalMKi8...Mh66mG9j7zfyQxsp7UPC4J"
}
```
2. Extract the first token, keyed `access_token` and ending `wmlxPjh49DYeEuh_w4vt2Q` in this example.
3. Call the [ListInstruments](https://www.lusid.com/docs/api/#operation/ListInstruments) API, passing in the `access_token`. Note here we are limiting the request to just the first instrument:

```powershell
curl -X GET https://<your-domain>.lusid.com/api/api/instruments?limit=1 
   -H "Authorization: Bearer eyJraWQiOiJvZDFzeFk4WTlPalMyZ2dZT3VidVBYT2dRX0dURkcwZ1...wmlxPjh49DYeEuh_w4vt2Q" | python3 -m json.tool
```

The response might be as follows (in this case piped through the Python [json.tool](https://docs.python.org/3/library/json.html#module-json.tool) module to make it easier to read):

```json
    "values": [
        {
            "scope": "default",
            "lusidInstrumentId": "CCY_EUR",
            "version": {
                "effectiveFrom": "0001-01-01T00:00:00.0000000+00:00",
                "asAtDate": "2024-07-26T14:29:32.6442480+00:00",
                "asAtCreated": "2020-12-01T09:19:38.1233560+00:00",
                "asAtModified": "2020-12-01T09:19:38.1233560+00:00",
                "asAtVersionNumber": 1,
                "entityUniqueId": "7d99b09a-1ca6-45c5-aa1e-28e16f64daa5",
                "stagedModificationIdModified": ""
            },
            "name": "EUR",
            "identifiers": {
                "LusidInstrumentId": "CCY_EUR",
                "Currency": "EUR"
            },
            "properties": [],
            "state": "Active",
            "assetClass": "Money",
            "domCcy": "EUR",
            "relationships": []
        }
    ]
}
```

## Step 4: Enabling the LUSID SDK to obtain an API access token on demand

Now we'll perform the same operation using v2 of the [LUSID Python SDK](/v1/docs/installing-or-upgrading-the-lusid-python-sdk) (available in [other languages and frameworks](/v1/docs/understanding-all-the-applications-in-the-finbourne-platform)).

The SDK has helper classes that automate the process of obtaining an API access token and refreshing it upon expiry, so we don't need to supply one directly. Instead, we store the username, password, client ID, client secret and dedicated Okta token URL either as environment variables or in a secrets file, and make it available to the SDK.

In this example we'll use a secrets file (alternatively, see the instructions for [environment variables](/v1/docs/how-do-i-use-an-api-access-token-with-the-lusid-sdk#using-environment-variables)):

1. Go back to the LUSID web app and select **Identity and access > Applications**.
2. On the **Applications** dashboard, click the ![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/4529b1c4-909f-4ed6-84b0-0746ae96d724.png) **View** icon for the application we created in [Step 2](/v1/docs/authorising-an-application-or-service-to-call-the-lusid-api#step-2-generating-a-client-id-and-client-secret).
3. In the **Export credentials** area, make sure **Secrets file** is selected and copy the data to the clipboard: ![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/74ac10af-287f-4007-a6d1-fa03a8e18c58.png)
4. Paste the data into an appropriate local file, for example `secrets.json`, supplying the user's actual LUSID password instead of `&lt;password&gt;`.

Providing `secrets.json` is in the same directory, the following script demonstrates generating an API access token automatically using the synchronous version of the SDK when the [InstrumentsApi.list_instruments](https://lusid-sdk-python.readthedocs.io/en/latest/_autosummary/sdk.lusid.api.instruments_api.InstrumentsApi.html#sdk.lusid.api.instruments_api.InstrumentsApi.list_instruments) method is called:

```python
# Setup:
import lusid, pprint
from lusid.extensions import SyncApiClientFactory

# Authenticate:
api_factory = SyncApiClientFactory()

# Build Instrument API and list first instrument:
instruments_api = api_factory.build(lusid.InstrumentsApi)
response = instruments_api.list_instruments(limit=1)
pprint.pprint(response.to_dict()["values"])
```

> **Note:** For an example of using the asynchronous version of the SDK, see the [Github readme](https://github.com/finbourne/lusid-sdk-python?tab=readme-ov-file#example).

The response is formatted slightly differently but contains the same information:

```json
[{'assetClass': 'Money',
  'domCcy': 'EUR',
  'identifiers': {'Currency': 'EUR', 'LusidInstrumentId': 'CCY_EUR'},
  'links': None,
  'lusidInstrumentId': 'CCY_EUR',
  'name': 'EUR',
  'properties': [],
  'relationships': [],
  'scope': 'default',
  'state': 'Active',
  'version': {'asAtCreated': datetime.datetime(2020, 12, 1, 9, 19, 38, 123356, tzinfo=datetime.timezone.utc),
              'asAtDate': datetime.datetime(2024, 7, 26, 13, 30, 0, 933026, tzinfo=datetime.timezone.utc),
              'asAtModified': datetime.datetime(2020, 12, 1, 9, 19, 38, 123356, tzinfo=datetime.timezone.utc),
              'asAtVersionNumber': 1,
              'effectiveFrom': datetime.datetime(1, 1, 1, 0, 0, tzinfo=datetime.timezone.utc),
              'entityUniqueId': '4b3a0cba-45cc-483b-857a-f273460bd5af',
              'requestIdCreated': None,
              'requestIdModified': None,
              'stagedModificationIdModified': '',
              'userIdCreated': None,
              'userIdModified': None}}]
```

Note if `secrets.json` is not in the same directory, or has a different file name, you must specify a `SecretsFileConfigurationLoader`:

```python
# Setup:
import lusid, pprint
from lusid.extensions import (
    SyncApiClientFactory,
    SecretsFileConfigurationLoader
)

# Authenticate:
secrets_path = "/path/to/secrets.json"
config_loaders=[
    SecretsFileConfigurationLoader(secrets_path)
]
api_factory = SyncApiClientFactory(config_loaders=config_loaders)

# Build Instrument API and list first instrument:
instruments_api = api_factory.build(lusid.InstrumentsApi)
response = instruments_api.list_instruments(limit=1)
pprint.pprint(response.to_dict()["values"])
```
