The DigAí Public API uses the OAuth 2.0 — Client Credentials Grant
(RFC 6749, section 4.4) for machine-to-machine authentication.
Instead of sending a static credential on every request, your application exchanges a
client_id + client_secret for a short-lived access token (a signed JWT) at our identity
provider, and uses that token to call the API. When the token expires, your application requests
a new one.
How it works
┌────────────┐ 1. client_id + client_secret + resource ┌─────────────────────┐
│ Your │ ───────────────────────────────────────────▶ │ Identity provider │
│ application│ ◀─────────── 2. access_token (JWT) ────────── │ (OAuth) │
└────────────┘ └─────────────────────┘
│
│ 3. Authorization: Bearer <access_token>
▼
┌─────────────────────┐
│ DigAí Public API │ 4. validates the token's signature, issuer and audience, then responds
└─────────────────────┘
- Your application authenticates at the identity provider with its credentials.
- It receives a short-lived
access_token(JWT). - It sends the token in the
Authorizationheader of every API call. - The API validates the token and processes the request.
Step by step
1. Request your credentials
Before integrating, request access to the DigAí Public API through your DigAí point of contact
(or the support channel), stating which environment(s) you need (staging and/or production).
DigAí will provision a dedicated application for you and send back:
- your
client_idandclient_secret; - the environment parameters — token endpoint (
AUTH_BASE_URL), API identifier (RESOURCE)
and API base (API_BASE_URL). See Environment parameters.
Store the client_secret in a secret manager — treat it as a long-lived secret and never expose
it in client-side code or version control.
2. Get an access token
Make a POST request to the identity provider's token endpoint:
curl --request POST \
--url "https://<domain>/oidc/token" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data "grant_type=client_credentials" \
--data "client_id=YOUR_CLIENT_ID" \
--data "client_secret=YOUR_CLIENT_SECRET" \
--data "resource=https://<domain>"Response:
{
"access_token": "eyJhbGciOiJFUzM4NCJ9.eyJ...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": ""
}access_token— the JWT to use on API calls.expires_in— lifetime in seconds. Use this value to decide when to refresh; do not assume
a fixed value.
3. Call the API
Send the token in the Authorization header:
curl --request GET \
--url "https://api-screening.digai.ai/api/v1/public/screenings" \
--header "Authorization: Bearer YOUR_ACCESS_TOKEN"4. Refresh the token
The access token is short-lived. Your application should:
- Reuse the same token while it is valid (do not request a new one on every call).
- Request a new token shortly before it expires (e.g. 30–60s before
expires_in) or when it
receives a401 Unauthorized.
No refresh_token is needed in the Client Credentials flow — just repeat step 2.
Environment parameters
The values below are provided by DigAí during onboarding, per environment (staging and
production):
| Parameter | Description |
|---|---|
AUTH_BASE_URL | Identity provider base (token endpoint) |
RESOURCE | Public API identifier (audience) |
API_BASE_URL | Public API base |
client_id | Your application identifier |
client_secret | Your application secret |
Production URLs are provided separately. Never commit theclient_secrettorepositories or plain-text configuration files.
Scopes
Scopes let a credential be limited to a subset of operations (least privilege). By default a
client is granted full access to its own resources; scoped access can be enabled per client on
request.
Example scope catalog:
| Scope | Grants |
|---|---|
screenings:read | List and read screenings |
screenings:write | Create, update and delete screenings |
questions:read | Read screening questions |
questions:write | Create and update screening questions |
candidates:read | Read candidates and their results |
candidates:write | Create and update candidates |
workspaces:read | Read workspaces |
When scoped access is enabled for your client, request the scopes at the token endpoint (space-
separated) and they are echoed back in the token response and enforced by the API:
curl --request POST \
--url "https://<domain>/oidc/token" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data "grant_type=client_credentials" \
--data "client_id=YOUR_CLIENT_ID" \
--data "client_secret=YOUR_CLIENT_SECRET" \
--data "resource=https://<domain>" \
--data "scope=screenings:read candidates:read"A request to an operation outside the granted scopes returns 403 Forbidden.
Security properties (for AppSec teams)
Technical reference for the integration's security assessment:
| Property | Detail |
|---|---|
| Protocol | OAuth 2.0 Client Credentials Grant (RFC 6749 §4.4) |
| Token format | Signed JWT (JWS). Algorithms: ES384 / RS256 |
| Signature verification | Public keys exposed via JWKS at AUTH_BASE_URL/oidc/jwks |
| Server-side validation | Signature, issuer (iss), audience (aud = Public API identifier) and expiry (exp) |
| Token lifetime | Short (reported in expires_in); refreshed automatically by the client |
| Secret exposure | The client_secret is sent only to the token endpoint, over TLS — it is never sent to the resource API |
| Transport | HTTPS/TLS required on all endpoints |
| Rotation / revocation | Centralized at the identity provider; credentials can be revoked or rotated with no changes to the API |
| Isolation | Each client has its own application (dedicated client_id); credentials are not shared between partners |
How this differs from a static API Key: with an API Key, the long-lived credential itself
travels on every request to the API. With OAuth 2.0, what travels to the API is an ephemeral
token; the long-lived credential (client_secret) only ever touches the token endpoint. If the
in-transit token is captured, it expires within minutes.
Error handling
| Status | Meaning | Recommended action |
|---|---|---|
401 Unauthorized | Missing, expired or invalid token | Get a new token and retry the request |
403 Forbidden | Valid token, but no access to the requested item | Check that the resource belongs to your account |
400 at token endpoint | Invalid client_id/client_secret/resource | Review the credentials and the resource value |
Migrating from the API Key
The legacy API Key stays valid during the transition, so migration can be done with no
downtime:
- Ask DigAí to create your OAuth 2.0 credentials (
client_id/client_secret). - Implement the access-token request (step 1) and start sending
Authorization: Bearer <token>. - Validate in staging.
- Switch authentication in production. Since the header is the same (
Authorization: Bearer ...),
the change is limited to how the token value is obtained. - After migrating, ask DigAí to revoke the old API Key.
