This page describes how authentication and authorization is implemented in the Live Data API.

Authentication

All API calls require authentication in the form of an access token, which can be obtained using a username/password or service account credentials via the OAuth2 token endpoint.

Service Accounts

Live Data uses the OAuth2 Client Credentials flow for authenticating service accounts. Create a Service Account using the UI by selecting the Teams menu on the left and the Service Accounts tab. When creating a service account, you will be provided the client secret -- this is the only time you can obtain the secret.

To authenticate using these credentials, call the Create a new session endpoint with grantType=clientCredentials and the clientId and clientSecret params populated by the service account ID and secret. This will return an access token which can be used to authenticate further calls.

Request

curl -X 'POST' \
  'https://gotlivedata.io/api/identity/v1/session' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "grantType": "clientCredentials",
  "clientId": "<your service account/client id>",
  "clientSecret": "<your client secret>"
}'

Response

{"accessToken": "eyJ0eXAiOiJKV1Qi.eyJ0eXAiOiJKV1Qi.4K20wYgWlrQ9y58-nBJU8", "expiresAt": "2021-11-19T23:36:09.092720"}

Obtaining an Access Token Using Username/Password

To obtain an access token using user credentials, call the Create a new session endpoint using your username and password.

curl -X POST https://gotlivedata.io/api/identity/v1/session \
  -d "username=<username>&password=<password>"

A successful response will be a 200 and include an access_token field in the body, along with the expiration time. Access tokens expire 1 hour after creation.

Using the access token

Use the accessToken provided in the response in any additional calls to any API. Place the token in a header called Authorization prefixed with Bearer, like below:

curl --request POST \
     --url https://gotlivedata.io/api/people/v1/o_123abc/find \
     --header 'accept: application/json' \
     --header 'authorization: Bearer eyJ0eXAiOiJKV1Qi.eyJ0eXAiOiJKV1Qi.4K20wYgWlrQ9y58-nBJU8' \
     --header 'content-type: application/json' \
     --data '
{
  "matches": [
    {
      "fields": [
        {
          "field_name": "email_address",
          "search_term": "[email protected]"
        }
      ]
    }
  ]
}
'

Authorization

All API calls require a defined 'role', which is specified in the API documentation. The user or service account making the API call must have the specified role on the organization for the API call to succeed.

Sample Python Auth Code

The code below demonstrates how you might incorporate LDT auth into a Python application.

LiveDataServiceAccount Class

import requests
import time
import calendar
from datetime import datetime, timezone

LOGIN_URL = "https://gotlivedata.io/api/identity/v1/session"


class LiveDataServiceAccount:
    def __init__(self, client_id: str, client_secret: str) -> None:
        self.client_id = client_id
        self.client_secret = client_secret
        self._access_token = None
        self._expires_at = None
        self._is_logging_in = False

    def _active(self):
        if not self._access_token:
            return False

        if not self._expires_at:
            return False

        now = time.time()
        will_expire_soon = self._expires_at - now < 25

        if will_expire_soon:
            return False

        return True

    def access_token(self) -> str:
        if self._is_logging_in:
            for _ in range(25):
                time.sleep(0.5)

                if not self._is_logging_in:
                    break

        if not self._active():
            self.login()

        return self._access_token

    def login(self) -> str:
        self._is_logging_in = True

        payload = {
            "clientId": self.client_id,
            "clientSecret": self.client_secret,
            "grantType": "clientCredentials"
        }

        resp = requests.post(url=LOGIN_URL, json=payload)
        if resp.status_code != 200:
            raise Exception("Login failed")

        body = resp.json()

        self._access_token = body.get("accessToken")
        self._expires_at = int(
            calendar.timegm(
                time.strptime(body.get("expiresAt"), "%Y-%m-%dT%H:%M:%S.%f")))

        self._is_logging_in = False

Usage

The class logs in and tracks when the token will expire, always keeping it active. Just call account.access_token() to have a valid token.

We new up a LD service account in the entrypoint and pass it to the run function.

account = LiveDataServiceAccount(
    client_id="",
    client_secret=""
)

api = DwhApi(livedata_service_account=account)

The below is an example of a class you might construct that targets a specific Live Data API and incorporates the LiveDataServiceAccount class for authentication.

class DwhApi:
    def __init__(self, livedata_service_account: LiveDataServiceAccount) -> None:
        self.livedata_service_account = livedata_service_account

    def get_company(self, company_lookup: str):
        url = f"{BASE_URL}/companies/{company_lookup}"
        headers = {
            "Authorization": f"Bearer {self.livedata_service_account.access_token()}"}
        response = requests.get(url, headers=headers)

        if response.status_code == 200:
            return response.json()

        raise Exception(f"Error: {response.status_code} - {response.text}")