Auth and Access
Two wires, one control plane, three roles. Both credential surfaces live in the console sidebar (SSH Keys and API Keys).
The three roles
Access is a role from Keycloak’s git-authorization-service, granted through IAM:
| Role | Grants |
|---|---|
git.admin | everything: settings, visibility, protection, delete |
git.editor | read + write (clone, push, PRs) — the common default |
git.viewer | read only |
A grant is either org-wide (all repos) or per-repo — an IAM permission role conditioned on the repo’s DRN (drn:dodil:git:{region}:{org}:repo/{repo_id}). Re-granting a principal on the same repo swaps the tier rather than stacking. The authoritative “who can touch this repo” roster lives in the IAM console; the repo’s Settings → Access panel manages individual principals and deep-links there.
Public repos allow anonymous read with no credential at all; writes always require one.
API keys (dk_…) — the HTTP wire
An org API key is the universal git credential for apps, CI, and integrations. Issued from the console’s API Keys page (or the IAM API), each key:
- is backed by a managed service account minted by IAM;
- carries one git role (
git.admin/git.editor/git.viewer), org-wide by default (per-repo DRN scoping via the IAM console); - has a secret shown exactly once, on issue and on rotate.
On the git wire the key is the HTTP Basic password — the username is ignored:
git clone https://user:[email protected]/<repo_id>.gitTo keep the secret out of shell history and remotes, use a credential helper:
git config credential.helper store
git clone https://git.dodil.io/<repo_id>.git # prompts once: any username, dk_ key as passwordThe same key authenticates the REST control plane and the CLI (--token dk_…). Rotation invalidates the old secret immediately; revocation is irreversible.
SSH keys — the SSH wire
Upload your public key once on the console’s SSH Keys page: a name plus the key in authorized_keys form (<type> <base64> [comment], e.g. ssh-ed25519 AAAA… you@laptop). Optionally mark it read-only — clone allowed, push rejected on the channel.
git clone [email protected]:<repo_id>.gitKeys are managed at GET/POST /api/v1/user/keys and DELETE /api/v1/user/keys/{key_id}; the list shows each key’s type, fingerprint, and last-used time.
The control plane
REST calls under /api/v1 accept either credential shape:
- Bearer JWT —
Authorization: Bearer <token>from Dodil SSO (dodil auth login; the console attaches it automatically, plus anx-organization-idtenancy header). - Basic with a
dk_key — the key as the password, as on the wire. The CLI picks the right scheme from the token shape.
Two failure modes, deliberately distinct: 401 = unauthenticated (missing/expired token — log in again); 403 = authenticated but lacking the grant (re-authing won’t help — you need a role).
See also
- Quickstart — issue a key and clone in five minutes
- CLI Guide — how the CLI resolves tokens and orgs
- API Reference — auth conventions on every endpoint