API Authentication#

Note

This document is about API authentication for anyone except robots. For robots, refer to HMAC Auth.

Background#

Interaction with the DESTINY Repository API requires first obtaining an authentication token from Azure. This token must then be included in the Authorization header of each API request.

        sequenceDiagram
    actor Client
    participant Azure
    participant API
    Client->>Azure: Request token (client credentials)
    Azure-->>Client: Return access token
    Client->>API: API request with Authorization: Bearer <token>
    API-->>Client: Return requested data
    

Provisioning#

In order to obtain a token from Azure, you will need to be enrolled in our tenant JT_AD. Please reach out if you need access.

Everyone will have reference.reader, but please reach out if you need additional permission scopes. You can see the available scopes per API resource in the API documentation - it is listed under each sub-category.

Obtaining a token#

There are a number of ways to obtain an OAuth2 token from Azure.

In all cases, you will need the following information:

Authentication Details#

Environment

Login URL

Client ID

Application ID

Development

https://login.microsoftonline.com/f870e5ae-5521-4a94-b9ff-cdde7d36dd35

0fde62ae-2203-44a5-9722-73e965325ae7

0a4b8df7-5c97-42b2-be07-2bb25e06dbb2

Staging

https://login.microsoftonline.com/f870e5ae-5521-4a94-b9ff-cdde7d36dd35

96ed941e-15dc-4ec0-b9e7-e4eda99efd2e

14e3f6c0-b8aa-46c6-98d9-29b0dd2a0f7c

Production

https://login.microsoftonline.com/f870e5ae-5521-4a94-b9ff-cdde7d36dd35

7164ff26-4078-4107-850f-57b43b97f605

e314440e-f72c-4b8e-89c1-7eefef4b55ed

Using the SDK#

This is the recommended way to obtain tokens, as the SDK will handle token caching and refreshing for you, and will be kept up to date with any changes to the API authentication process.

class destiny_sdk.client.OAuthMiddleware(azure_client_id: str, azure_application_id: str, azure_login_url: HttpUrl | str | None = None, azure_client_secret: str | None = None, *, use_managed_identity: bool = False)[source]

Auth middleware that handles OAuth2 token retrieval and refresh.

This is generally used in conjunction with OAuthClient.

Supports three authentication flows:

Public Client Application (human login)

Initial login will be interactive through a browser window. Subsequent token retrievals will use cached tokens and refreshes where possible, and only prompt for login again if necessary.

auth = OAuthMiddleware(
    azure_client_id="client-id",
    azure_application_id="login-url",
    azure_tenant_id="tenant-id",
)

Confidential Client Application (client credentials)

Suitable for service-to-service authentication where no user interaction is possible or desired. Reach out if you need help setting up a confidential client application. The secret must be stored securely.

auth = OAuthMiddleware(
    azure_client_id="client-id",
    azure_application_id="application-id",
    azure_login_url="login-url",
    azure_client_secret="your-azure-client-secret",
)

Azure Managed Identity

Suitable for Azure environments that have had API permissions provisioned for their managed identity. Note that the azure_client_id here is the client ID of the managed identity, not the repository.

auth = OAuthMiddleware(
    azure_client_id="your-managed-identity-client-id",
    azure_application_id="application-id",
    use_managed_identity=True,
)

Using a script#

You can obtain a token programmatically using libraries such as MSAL for Python.

from msal import PublicClientApplication

app = PublicClientApplication(
    client_id="<your-client-id>",
    authority="<your-login-url>",
    client_credential=None,
)
token = app.acquire_token_interactive(
    scopes=["api://<application-id>/.default"]
)
access_token = token["access_token"]

Using the token#

The API base URL for each environment is as follows:

Using the SDK#

Again, we recommend using the SDK to make API requests, as it will handle including the token for you. Some endpoints will have convenience methods available, otherwise you can access the underlying httpx client directly.

class destiny_sdk.client.OAuthClient(base_url: HttpUrl | str, auth: Auth | None = None)[source]

Client for interaction with the Destiny API using OAuth2.

This will apply the provided authentication, usually OAuthMiddleware, to all requests. Some API endpoints are supported directly through methods on this class, while others can be accessed through the underlying httpx client.

Example usage:

from destiny_sdk.client import OAuthClient, OAuthMiddleware

client = OAuthClient(
    base_url="https://destiny-repository.example.com",
    auth=OAuthMiddleware(...),
)

# Supported method
response = client.search(query="example")

# Unsupported method, use underlying httpx client
response = client.get_client().get("/system/healthcheck/")

Using directly#

When making API requests, include the token in the Authorization header following Bearer, eg:

import httpx

httpx.get(
    api_url + "/v1/references/search/?q=example",
    headers={"Authorization": "Bearer <access_token>"},
)

The tokens will expire after a certain period (usually two hours). After expiration, you will need to obtain a new token using the same method as before.

Script template#

# Easy access of configurations listed in the tables above
CONFIGS = {
    "development": {
        "url": "https://destiny-repository-deve-app.gentlecoast-c1c9497a"
               ".swedencentral.azurecontainerapps.io",
        "login_url": "https://login.microsoftonline.com/f870e5ae-5521-4a94-b9ff-cdde7d36dd35",
        "client": "0fde62ae-2203-44a5-9722-73e965325ae7",
        "app": "0a4b8df7-5c97-42b2-be07-2bb25e06dbb2",
    },
    "staging": {
        "url": "https://destiny-repository-stag-app.proudmeadow-2a76e8ac"
               ".swedencentral.azurecontainerapps.io",
        "login_url": "https://login.microsoftonline.com/f870e5ae-5521-4a94-b9ff-cdde7d36dd35",
        "client": "96ed941e-15dc-4ec0-b9e7-e4eda99efd2e",
        "app": "14e3f6c0-b8aa-46c6-98d9-29b0dd2a0f7c",
    },
    "production": {
        "url": "https://destiny-repository-prod-app.politesea-556f2857"
               ".swedencentral.azurecontainerapps.io",
        "login_url": "https://login.microsoftonline.com/f870e5ae-5521-4a94-b9ff-cdde7d36dd35",
        "client": "7164ff26-4078-4107-850f-57b43b97f605",
        "app": "e314440e-f72c-4b8e-89c1-7eefef4b55ed",
    },
}

# Select environment
ENV = "staging"

### Option 1: Use the SDK (recommended)
from destiny_sdk.client import OAuthClient, OAuthMiddleware
client = OAuthClient(
    base_url=CONFIGS[ENV]["url"],
    auth=OAuthMiddleware(
        azure_client_id=CONFIGS[ENV]["client"],
        azure_application_id=CONFIGS[ENV]["app"],
        azure_login_url=CONFIGS[ENV]["login_url"],
    ),
)
response = client.search(query="example")
print(response)

### Option 2: Use MSAL directly
from msal import PublicClientApplication
import httpx
import json

# Authenticate and get auth token
app = PublicClientApplication(
    client_id=CONFIGS[ENV]["client"],
    authority=CONFIGS[ENV]["login_url"],
    client_credential=None,
)
token = app.acquire_token_interactive(
    scopes=[f"api://{CONFIGS[ENV]['app']}/.default"]
)

# Request data from DESTinY API
response = httpx.get(
    f"{CONFIGS[ENV]['url']}/v1/references/search/?q=example",
    headers={"Authorization": f"Bearer {token["access_token"]}"},
)

# Use response
print(json.dumps(response.json(), indent=2))

Troubleshooting#

Please reach out if you experience any issues both obtaining or using tokens - most likely, we need to update some permissions.