Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Authentication

ScaiDNS supports two authentication methods: JWT tokens issued by ScaiKey for interactive users, and API keys for machine clients. Every API request uses one or the other.

Use API keys for servers, CI, and automation. Use JWTs when a human is in the loop.

API keys#

API keys are the simplest option and recommended for any non-interactive caller.

Create a key#

From the admin UI: API Keys → Create. A key needs:

  • Name. A label shown in listings and audit logs. Pick something specific.
  • Permission source. A user or a group. The key inherits permissions from whichever you pick. This is the mechanism that gives the key any access at all.
  • Optional rate limit. Requests per minute. Omit for unlimited (subject to platform limits).
  • Optional IP whitelist. CIDR blocks. Requests from outside are rejected with 403.
  • Optional expiry. Timestamp after which the key is refused. Omit for no expiry.

Creation returns the full secret exactly once:

json
1
2
3
4
5
6
7
8
{
  "id": "key_a1b2c3d4",
  "name": "ci-production",
  "key": "sdk_live_f7a9...",
  "permission_source": "user",
  "permission_source_id": "u_...",
  "created_at": "2026-04-23T10:00:00Z"
}

Store key in a secret manager immediately. ScaiDNS does not store it in plaintext — you cannot retrieve it later. If lost, regenerate via POST /api/v1/api-keys/{key_id}/regenerate (invalidates the old secret).

Use a key#

Send the key in the X-API-Key header:

bash
1
2
curl https://scaidns.scailabs.ai/api/v1/domains/ \
  -H "X-API-Key: $SCAIDNS_API_KEY"
python
1
2
3
4
5
6
import os, httpx

resp = httpx.get(
    "https://scaidns.scailabs.ai/api/v1/domains/",
    headers={"X-API-Key": os.environ["SCAIDNS_API_KEY"]},
)
typescript
1
2
3
const resp = await fetch("https://scaidns.scailabs.ai/api/v1/domains/", {
  headers: { "X-API-Key": process.env.SCAIDNS_API_KEY! },
});

Revoke vs delete#

  • Revoke (POST /api/v1/api-keys/{id}/revoke) disables the key. You can re-activate it later. Use this when the key might come back.
  • Delete (DELETE /api/v1/api-keys/{id}) removes the key permanently. Use this when it's compromised or permanently retired.

JWT tokens#

Human users authenticate through ScaiKey's OAuth 2.0 authorization code flow with PKCE. ScaiDNS itself is the OAuth client, the frontend handles the browser redirect.

The three relevant endpoints:

Endpoint Purpose
GET /api/v1/auth/config OAuth configuration — authorization and token endpoints, client ID, scopes
POST /api/v1/auth/token Exchange an authorization code for access + refresh tokens
POST /api/v1/auth/refresh Exchange a refresh token for a new access token

Full flow#

  1. Fetch config. Call GET /api/v1/auth/config to discover the authorization endpoint, client ID, and scopes.

  2. Generate PKCE pair. Generate a code_verifier (random string) and derive code_challenge = base64url(sha256(code_verifier)).

  3. Redirect to ScaiKey. Send the user to {authorization_endpoint}?response_type=code&client_id=...&redirect_uri=...&scope=...&state=...&code_challenge=...&code_challenge_method=S256.

  4. Receive callback. ScaiKey redirects back to your redirect_uri with ?code=...&state=.... Verify state matches what you sent.

  5. Exchange for tokens. POST /api/v1/auth/token with the code and verifier:

    bash
    1
    2
    3
    4
    5
    6
    7
    curl -X POST https://scaidns.scailabs.ai/api/v1/auth/token \
      -H "Content-Type: application/json" \
      -d '{
        "code": "authcode_from_callback",
        "code_verifier": "your_pkce_verifier",
        "redirect_uri": "https://your-app.example.com/oauth/callback"
      }'
    

    Response:

    json
    1
    2
    3
    4
    5
    6
    7
    {
      "access_token": "eyJhbGc...",
      "refresh_token": "eyJhbGc...",
      "token_type": "Bearer",
      "expires_in": 3600,
      "id_token": "eyJhbGc..."
    }
    
  6. Use the access token. Send Authorization: Bearer <access_token> on every request.

  7. Refresh when expired. When the access token expires, POST /api/v1/auth/refresh with the refresh token. You get a fresh access token.

If you are building a first-party frontend, the reference implementation in the ScaiDNS admin UI demonstrates the full flow — look at authStore.ts.

Using a JWT in requests#

bash
1
2
curl https://scaidns.scailabs.ai/api/v1/me \
  -H "Authorization: Bearer $ACCESS_TOKEN"
python
1
2
3
4
resp = httpx.get(
    "https://scaidns.scailabs.ai/api/v1/me",
    headers={"Authorization": f"Bearer {access_token}"},
)
typescript
1
2
3
const resp = await fetch("https://scaidns.scailabs.ai/api/v1/me", {
  headers: { Authorization: `Bearer ${accessToken}` },
});

Scope and tenant#

Both authentication methods resolve to a tenant context. Every API request operates within a tenant:

  • API keys are bound to a tenant at creation. The tenant of the key's owning user (or group's tenant) is used.
  • JWT tokens carry tenant info in their claims. ScaiDNS resolves this to the internal tenant UUID on each request.

You cannot make cross-tenant calls with a non-admin key or token. Platform admins can see and mutate across tenants; see Permissions and Access.

Errors#

Status Meaning Action
401 Unauthorized No credentials, invalid JWT, or invalid API key Check the header is set and the key/token hasn't expired
403 Forbidden Authenticated, but the caller lacks permission Check role assignments, domain access grants, or IP whitelist
429 Too Many Requests Rate limit exceeded Back off; inspect key's rate limit config

Which should I use?#

Situation Use
A CI job mutating DNS API key scoped to a service user or group
A Terraform provider API key
A first-party frontend with human users JWT via OAuth
A CLI on an operator's laptop Either — API key for simplicity, JWT if audit needs to show the individual human
A one-off admin script JWT if interactive (they log in once), API key if scheduled

What's next#

Updated 2026-05-17 02:38:19 View source (.md) rev 1