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_secretatid.dodil.io(OAuth client-credentials) for a short-lived JWT, then sendAuthorization: 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 acceptdk_keys.
API key (dk_…) | Service account JWT | |
|---|---|---|
| Obtain | issued once, sent as-is | exchange client_id/secret → JWT per session |
| Lifetime | long-lived (until rotate/revoke or --ttl) | short-lived, refresh on expiry |
| Verified by | private IAM lookup (hash fetch + local argon2 check) | signature check against public JWKS — anywhere |
| Edge / worker-cluster endpoints | No — rejected with 401 | Yes |
Where API keys work
| Surface | dk_ 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]--roleis required (e.g.k3.editor,registry.developer,git.ci).--servicepicks the resource plane the role applies to (defaultk3).--drn(repeatable) scopes the grant to specific resources; omit it for an org-wide grant.--ttlsets 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
| Form | How | When |
|---|---|---|
| Bearer | Authorization: Bearer dk_… (the full token) | REST / gRPC APIs — the default |
| Basic | the full dk_… token as the password in Basic auth; the username is ignored | docker login, git over HTTPS, tools that only speak Basic |
| S3 SigV4 | dk_{lookup} (the public half) as the access key ID | S3 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 eitherdk_{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:
| Role | Grants |
|---|---|
k3.viewer | read-only on K3 (storage, tables, vector) |
k3.editor | read/write on K3 |
k3.admin | full K3 administration |
registry.developer | push/pull on the container registry |
git.ci | CI access to git repositories |
org.owner | full 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 tableA 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 logindoes not acceptdk_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
- Service Accounts — the underlying principal an API key binds to
- Roles and Policies — what a key is allowed to do
- Get an Access Token — when you need a short-lived JWT instead