Skip to Content
We are live but in Staging 🎉
IAMAPI Keys

API Keys

A Dodil API key is the primary credential for programmatic access — CI jobs, SDK clients, docker login, and any headless caller. It is a single opaque token you send directly with each request: no OAuth exchange, no token refresh.

API key vs service account — which and where

An API key and a service account are semantically different credentials, not two spellings of the same thing:

  • A service account does a token dance: you exchange its client_id + client_secret at id.dodil.io (OAuth client-credentials) for a short-lived JWT, then send Authorization: Bearer <jwt>. Because JWTs are signed and verifiable against public JWKS, any Dodil endpoint can verify one locally — including edge and worker-cluster gateways.
  • An API key (dk_…) is a long-lived direct credential: no exchange, no expiry-refresh loop — you send the token itself. The receiving gateway verifies it by fetching the key’s argon2id hash from IAM over a private gRPC service (ApiKeyService/GetApiKeyHash) and checking the secret locally. That private IAM hop is the catch: only gateways with private connectivity to IAM can accept dk_ keys.
API key (dk_…)Service account JWT
Obtainissued once, sent as-isexchange client_id/secret → JWT per session
Lifetimelong-lived (until rotate/revoke or --ttl)short-lived, refresh on expiry
Verified byprivate IAM lookup (hash fetch + local argon2 check)signature check against public JWKS — anywhere
Edge / worker-cluster endpointsNo — rejected with 401Yes

Where API keys work

Surfacedk_ accepted?
Control-plane APIs — IAM, git, registry, Ignite deploy/manage/models, DataK³ admin (api.dodil.io, api.data.dodil.io, git.dodil.io, registry)
DataK³ data wires — pg, S3/object, Bolt, Qdrant, Pinecone, GraphQL, gRPC tables✓ — the gateway tier terminates the key and forwards a short-lived signed session context  to the data clusters
Ignite worker / invoke endpoints (direct app invocation on worker clusters)✗ — use a service-account JWT

Worker-cluster gateways have no path to IAM, so they reject dk_ fast with 401 and accept Keycloak JWTs only. There is no public endpoint to verify a key against and no way to exchange a dk_ key for a JWT — if a workload must call edge endpoints, give it service-account credentials instead.

What an API key is

The wire token has the shape:

dk_{lookup}{secret}
  • dk_ — the fixed prefix.
  • lookup — 16 base32 characters, the public half. It identifies the key (it’s what you see in listings, and what rotate/revoke commands take).
  • secret — the private half. Only a hash of it is stored server-side, so it is shown exactly once at issuance. Save it immediately.

Every API key is bound to a principal — normally a service account — and carries one or more role grants. When a request arrives with the key, Dodil resolves it to that principal, its organization, and its granted roles.

Issue a key

Console

  • Bucket → API Keys — issue a key pre-scoped to that bucket.
  • Org → API Keys — issue an org-wide key.

The secret is displayed once on creation — copy it before closing the dialog.

CLI

dodil auth apikey issue --name <n> --role k3.editor \ [--service k3|git|registry] \ [--drn <resource-drn>] \ [--ttl 720h]
  • --role is required (e.g. k3.editor, registry.developer, git.ci).
  • --service picks the resource plane the role applies to (default k3).
  • --drn (repeatable) scopes the grant to specific resources; omit it for an org-wide grant.
  • --ttl sets an expiry from now (default: no expiry).

With no --sa/--user flag, IAM automatically mints a managed service account and binds the key to it — this is the simple path; you don’t need to create anything first. Pass --sa <clientId> or --user <id> only when you want the key bound to an existing principal.

The three wire forms

FormHowWhen
BearerAuthorization: Bearer dk_… (the full token)REST / gRPC APIs — the default
Basicthe full dk_… token as the password in Basic auth; the username is ignoreddocker login, git over HTTPS, tools that only speak Basic
S3 SigV4dk_{lookup} (the public half) as the access key IDS3 SDKs against object storage — see the caveat below

The Bearer and Basic forms are accepted by k3-api, the tables-gateway, and the object-gateway.

SigV4 signing secret. SigV4 is symmetric HMAC, so the SDK needs a signing secret — and it is not the dk_ token’s secret half (that half is only the Bearer/Basic credential). The signing secret is the client secret of the service account the key is bound to. The access key ID may be either dk_{lookup} or the SA’s clientId directly. See K3 → S3 Compatibility  for full SDK setup.

Roles and resource scoping

A key’s grants use the same roles as any other principal. The common ones:

RoleGrants
k3.viewerread-only on K3 (storage, tables, vector)
k3.editorread/write on K3
k3.adminfull K3 administration
registry.developerpush/pull on the container registry
git.ciCI access to git repositories
org.ownerfull organization control

Scope a grant to specific resources with a DRN. K3 DRNs have the shape:

drn:dodil:k3:{region}:{org}:bucket/{name} # a bucket drn:dodil:k3:{region}:{org}:bucket/{name}/dir/{prefix} # a directory prefix drn:dodil:k3:{region}:{org}:bucket/{name}/table/{table} # a table

A key with no DRN scope acts org-wide within its role.

Rotate and revoke

dodil auth apikey list # LOOKUP, NAME, PRINCIPAL, STATUS dodil auth apikey rotate <lookup> # new secret shown once; old secret stops working dodil auth apikey revoke <lookup> # delete the key
  • Rotate keeps the same lookup — the principal, grants, and (for SigV4) the access key ID are untouched; only the secret half changes.
  • Revoke propagates to all gateways within ~30 seconds.

Notes

  • The secret is shown once — at issue and at rotate. Store it in a secret manager, never in source control.
  • dodil auth login does not accept dk_ keys — they authenticate API requests, not the interactive CLI session.
  • If you need short-lived JWTs — or must call edge/worker endpoints where dk_ is rejected — use the client-credentials flow with a service account.

See also