Issuing identities

A developer signs in through your identity provider and mints an identity for their own workspace. The human on the identity is always the login, never a form field.

The issuing service

issuer-web (npm run issuer-web, Compose service issuer-web in compose.enterprise.yaml) is served by the same oauth2-proxy as approvals, at /issuer/. A developer enters:

  • a runtime ID, agent, team, and work mode;
  • an optional task (jira:PAY-12, servicenow:CHG0030001), GitHub login, and application;
  • the fingerprint printed by agentgate fingerprint in their workspace;
  • a lifetime up to AGENTGATE_ISSUER_MAX_TTL (default 24 hours).

They receive an assertion shown once. Save it, point AGENTGATE_RUNTIME_ASSERTION_PATH at it, and run agentgate renew in the workspace. It only works with the workspace token whose fingerprint was entered.

Why a fingerprint

An assertion is bound to the SHA-256 of the workspace's client token. The developer sends the hash, so the token itself never leaves their machine, and the issuer never holds a credential that could act as the workspace.

The delegable team

With AGENTGATE_ISSUER_DIRECTORY_FILE set to a directory export in the entitlements.static format, the team must be one the developer holds, and a directory failure issues nothing.

For live data instead of an export, point AGENTGATE_ISSUER_ENTITLEMENTS_FILE at a JSON file in the broker's entitlements shape with any of static, okta, and entra (see Entitlements). The union of teams and groups those sources report for the login is what the developer may claim, resolved live on every issuance; a source outage issues nothing (503).

The dashboard

The dashboard lists the developer's runtimes with agent, team, mode, task, expiry, and status (active, expired, revoked) and a revoke button. Administrators listed in AGENTGATE_ISSUER_ADMINS see and may revoke every runtime.

Revoking writes revocations.json, which agentd mounts read-only as AGENTGATE_REVOCATIONS_FILE and re-reads within AGENTGATE_REVOCATIONS_POLL_MS (default 5 seconds) with no operator action. Issuance and revocation are recorded in an append-only issued.jsonl that never contains the assertion, only its claims and the token fingerprint.

Configuration

VariableMeaning
AGENTGATE_ISSUER_KEY_PATHEd25519 private key (owner-only); only its public key goes into the broker's identity.issuers with the same kid
AGENTGATE_ISSUER_KID / AGENTGATE_ISSUER_AUDIENCEMust match the broker's issuer kid and identity.audience
AGENTGATE_ISSUER_ADMINSComma-separated emails that see and may revoke every runtime
AGENTGATE_ISSUER_MAX_TTLLongest assertion a developer may mint, seconds (60–86400)
AGENTGATE_ISSUER_DIRECTORY_FILEDirectory export bounding delegable teams
AGENTGATE_ISSUER_ENTITLEMENTS_FILELive sources (static, okta, entra) for the same purpose
AGENTGATE_ISSUER_BASE_PATH/issuer when sharing oauth2-proxy with approvals

The issuer trusts X-Forwarded-Email only alongside the proxy secret oauth2-proxy injects, restricts email domains like approval-web, signs every form with a CSRF token bound to the login and action, and sends the same hardening headers.

Automation

scripts/issue-runtime.js mints the same assertions from the command line, for CI or scripted rollouts. Bind with --client-token-file when the issuer created the token, or --client-token-sha256 with the developer's fingerprint. See Onboarding a company.

Warning

Whoever can run the script with the issuer key can mint any identity. Keep the script's key separate from the service's, or off developer-reachable hosts entirely. With identity.delegation: "enforce", the broker also re-checks the team claim against its own sources on every request; see Runtime identity.