Skip to Content
We are live but in Staging 🎉
Auth and Access

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:

RoleGrants
git.admineverything: settings, visibility, protection, delete
git.editorread + write (clone, push, PRs) — the common default
git.viewerread 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>.git

To 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 password

The 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>.git

Keys 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 JWTAuthorization: Bearer <token> from Dodil SSO (dodil auth login; the console attaches it automatically, plus an x-organization-id tenancy 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