Authentication

Available to: Developers (license type) Minimum plan: Free

TitanRDM's API uses OAuth 2.0 (via Doorkeeper) for authentication. This page explains how to obtain access tokens and use them to authenticate API requests.


Prerequisites

  • An OAuth Application created in TitanRDM (see OAuth Applications)
  • Your application's Client ID and Client Secret

Grant Types

TitanRDM supports two OAuth 2.0 grant types:

Client Credentials (Machine-to-Machine)

Use this for automated pipelines, ETL jobs, and services that don't act on behalf of a specific user.

When to use: - CI/CD pipelines importing or exporting data - Scheduled sync jobs - Monitoring and reporting scripts

Limitations: - No user context — actions are not attributed to a specific user, unless the application has a service account - Some endpoints require user context (deployments, promotions, CI/CD) and return 401 unless the application has a service account. Link one to promote and deploy from a pipeline; see CI/CD Integration.

Authorization Code (User Context)

Use this for integrations that act on behalf of a specific user, where actions need to be attributed and permissions need to be evaluated per-user.

When to use: - Custom admin tools or dashboards - Integrations where audit trail must show which user performed the action - Deployment and promotion automation as a specific person (pipelines can use a service account with Client Credentials instead)


Obtaining an Access Token

Client Credentials Flow

curl -X POST https://{subdomain}.app.titanrdm.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "scope=api"

You can also use HTTP Basic authentication for the client credentials:

curl -X POST https://{subdomain}.app.titanrdm.com/oauth/token \
  -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "scope=api"

Successful response:

{
  "access_token": "eyJhbGciOiJIUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 7200,
  "scope": "api",
  "created_at": 1700000000
}

Authorization Code Flow

  1. Redirect the user to the authorization endpoint:
https://{subdomain}.app.titanrdm.com/oauth/authorize?
  client_id=YOUR_CLIENT_ID&
  redirect_uri=YOUR_REDIRECT_URI&
  response_type=code&
  scope=api
  1. User grants access — they are redirected to your redirect_uri with a code parameter.

  2. Exchange the code for an access token:

curl -X POST https://{subdomain}.app.titanrdm.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=YOUR_REDIRECT_URI"

Successful response:

{
  "access_token": "eyJhbGciOiJIUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 7200,
  "refresh_token": "abc123...",
  "scope": "api",
  "created_at": 1700000000
}

Using an Access Token

Include the token in the Authorization header of every API request:

curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  https://{subdomain}.app.titanrdm.com/api/v1/domains

Token Expiration and Refresh

  • Access tokens expire after 2 hours (7200 seconds) by default
  • When using the Authorization Code flow, a refresh token is provided
  • Use the refresh token to obtain a new access token without re-authenticating the user:
curl -X POST https://{subdomain}.app.titanrdm.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "refresh_token=YOUR_REFRESH_TOKEN"

For the Client Credentials flow, simply request a new token when the current one expires.


Scopes

Request specific scopes to limit what the token can do:

ScopeAccess Level
apiBase scope included in every token. Required, but grants no access on its own
api:readRead-only (GET requests)
api:writeCreate and update (POST, PATCH, PUT)
api:deleteDelete resources (DELETE)
api:adminAdministrative operations

Request multiple scopes by separating with spaces:

scope=api:read api:write

Scopes are enforced per-request based on the HTTP method: - GET / HEAD → requires api:read - POST / PATCH / PUT → requires api:write - DELETE → requires api:delete

The base api scope does not satisfy these checks: request each scope your integration needs.


Tenant Context

TitanRDM is multi-tenant. The API automatically determines your account (tenant) from the OAuth application:

  • Client Credentials: Tenant is set from the OAuth application's account. If the application has a service account, requests act as that service account.
  • Authorization Code: Tenant is set from the authenticated user's account

The API verifies that the token's application account matches the user's account. Cross-account access is not permitted.


Error Responses

StatusErrorCause
401Invalid tokenToken is expired, revoked, or malformed
401Invalid resource ownerUser associated with the token no longer exists
401Token/user account mismatchToken application and user belong to different accounts
401Tenant context not setAuthentication failed completely
401The application's service account is unavailableThe application's service account is locked or has been removed
403Insufficient scope. Required: api:writeToken does not have the required scope for this action

Security Best Practices

  • Never expose client secrets in client-side code, public repositories, or logs
  • Use the minimum scope needed — request api:read if you only need to read data
  • Store tokens securely — use environment variables or a secrets manager
  • Rotate secrets periodically — use the "Regenerate Secret" feature in OAuth Applications
  • Use Client Credentials for service accounts, Authorization Code for user-facing integrations
  • Monitor API usage — check your account's usage dashboard for unexpected spikes