Machines & tokens
Service accounts, deploy tokens, and secrets. How non-human clients authenticate and what they can access.
How it works
Machines authenticate differently than people. gittan has four credential types, each scoped to what the machine actually needs:
| Type | Scope | Access | Lifetime | Use case |
|---|---|---|---|---|
| Service account | Org | Read + Write | No expiry | CI/CD automation, API scripts |
| Deploy token | Org | Read-only | Configurable | Image pull, npm install |
| Workload token | Repo | Read + scoped write | Pipeline duration | Pipeline identity (automatic) |
| Pipeline secret | Org / Team / Repo | Injected as env | No expiry | Secrets in pipeline steps |
Service accounts
A service account is an OAuth2 client_credentials client
registered to an org. It gets a client_id and client_secret that can be exchanged for an access token
with full read and write access to the org’s API.
Use service accounts for CI/CD systems, automation scripts, or any integration that needs to create repos, manage teams, trigger pipelines, or push code.
Deploy tokens
A deploy token is a read-only JWT for pulling packages and container images from
the gittan registry. The token’s scope is limited to pkg:read and img:read —
any write attempt is rejected at the gateway.
Use deploy tokens for Kubernetes imagePullSecret, docker pull in external CI,
or .npmrc tokens
for consuming private packages.
Workload tokens
Workload tokens are short-lived JWTs minted automatically for each pipeline run. They grant read access to the org’s registries and scoped write access limited to the repo’s declared image names. You never create or manage these — gittan handles the full lifecycle.
See Pipeline identity for the full token scope model, sandbox enforcement, and trust boundaries.
Pipeline secrets
Secrets are encrypted values injected into pipeline steps as environment variables. They exist at three levels:
- Org — available to every pipeline in the org.
- Team — available to every repo in the team.
- Repo — available only to that repo’s pipelines.
When the same secret name exists at multiple levels, the narrowest scope wins:
repo overrides team, team overrides org. Reference them in your pipeline config
as ${{ secrets.NAME }}.
Values are encrypted at rest. List endpoints return names and metadata only — values are never exposed after creation.
Credential helper
For humans using git over HTTPS, the credential helper exchanges your login token for a short-lived git token:
git config --global credential.https://git.gittan.eu.helper 'gittan credential' The helper reads your stored OIDC token, mints a Forgejo-level git token via the API, and caches it locally. No passwords are ever written to disk.
Setting it up
Creating a service account
Only org owners can create service accounts.
gittan service-accounts create --name ci-deploy --org <org-id> This returns a client_id and client_secret.
The secret is shown exactly once — store it immediately.
To authenticate, use a standard OAuth2 client_credentials grant
against auth.gittan.eu:
curl -X POST https://auth.gittan.eu/oauth/token \
-d grant_type=client_credentials \
-d client_id=<client_id> \
-d client_secret=<client_secret> \
-d scope="openid read write" Managing service accounts
# List all service accounts
gittan service-accounts list --org <org-id>
# Delete (revoke) a service account
gittan service-accounts delete --client-id <client-id> --org <org-id> Rotation
Service accounts have no built-in expiry. To rotate credentials, delete the
existing account and create a new one. Update any systems that reference the
old client_id and client_secret.
Creating a deploy token
Deploy tokens are created via the API (org owner required):
POST /orgs/:orgId/deploy-tokens The response includes the JWT, its expiry, the granted scope, and the registry URLs to configure in your cluster or CI:
| Field | Description |
|---|---|
| token | The JWT to use for authentication. |
| expiresAt | Token expiry timestamp. |
| scope | pkg:read:<org> img:read:<org> |
| registries.npm | npm registry URL for .npmrc. |
| registries.images | Container registry hostname for docker login. |
Managing secrets
Set secrets at the level that matches their blast radius:
# Org-wide — available to all pipelines
gittan secrets set org --name NPM_TOKEN --value <value> --org-id <id>
# Team — available to the team's repos
gittan secrets set team --name DB_URL --value <value> --team-id <id>
# Repo — single repo only
gittan secrets set repo --name API_KEY --value <value> --org-id <id> --repo-id <id> Listing and deleting
# List secrets (names and metadata only — values are never returned)
gittan secrets list org --org-id <id>
gittan secrets list team --team-id <id>
gittan secrets list repo --org-id <id> --repo-id <id>
# Delete a secret
gittan secrets delete org --name NPM_TOKEN --org-id <id>