Skip to content

HTTP API

The broker answers JSON. A refusal is {"code": "…", "error": "…"} with the HTTP status below; the error reference lists every code.

Each route takes one kind of credential, or none. These are the refusals the broker answers for the credential itself, before the route runs.

Credential Description Refusals
Machine credential A route for a machine’s launcher (agent-secrets-helper, or the Legion daemon), which signs each call’s Proof header with the key its machine login’s credential is bound to. 503 DATABASE_UNAVAILABLE
401 LAUNCHER_INVALID
None A route anyone may call, with no credential. none
Renewal session proof Session authentication for the one route that gives an ended enrollment a distinct refusal. A skewed/malformed proof remains PROOF_INVALID; only proof.ErrNotLive is ENROLLMENT_NOT_LIVE so the pod renewer can stop rather than retry an enrollment that cannot recover. 503 DATABASE_UNAVAILABLE
401 ENROLLMENT_NOT_LIVE
401 PROOF_INVALID
Session proof A route for an enrolled agent session, which signs each call’s Proof header with its own key, and which acts only on its own enrollment, requests and grants. 503 DATABASE_UNAVAILABLE
401 PROOF_INVALID
Dispatch token A route for Dispatch’s server, which sends the broker’s UI token as a bearer token and names the person acting (the approver) in the body or query. The broker trusts that name, so the UI token is an approval credential: only Dispatch’s server holds it. 401 UI_INVALID
Method Path Credential What it does
POST /v1/enrollments Machine credential Enroll a session’s or pod’s signing key under the caller’s machine credential.
DELETE /v1/enrollments/{id} Machine credential Revoke an enrollment made under the caller’s machine credential’s operator, or a pod enrollment the caller’s own machine credential made.
POST /v1/launcher-credentials None Start a person’s machine login: answers the confirmation code they type and a pending id.
POST /v1/launcher-credentials/token None Log a service in with its own Kubernetes ServiceAccount token, which no person approves: answers its launcher credential’s id and expiry.
GET /v1/launcher-credentials/{pending} None Poll a machine login by its pending id; once approved, answers its credential’s id.
POST /v1/enrollments/{id}/renew Renewal session proof Extend the calling session’s lease.
GET /v1/enrollments/self Session proof Describe the calling session’s enrollment and its live grants.
POST /v1/requests Session proof Request secrets: the policy grants or denies them at once, or a person must approve them.
GET /v1/requests/{id} Session proof Read one of the calling session’s requests.
POST /v1/requests/{id}/cancel Session proof Cancel one of the calling session’s pending requests.
POST /v1/grants/{id}/values Session proof Release a live grant’s values to the session that holds it.
POST /v1/grants/{id}/revoke Session proof End a grant the calling session holds.
GET /v1/pending Dispatch token List the pending requests and machine logins the named person decides.
GET /v1/credential-requests/{record} Dispatch token Read a credential-request record: what was asked, by whom, why, and its decision.
POST /v1/credential-requests/{record}/approve Dispatch token Approve a pending record as the named person; a machine login also needs its code.
POST /v1/credential-requests/{record}/deny Dispatch token Deny a pending record as the named person; a machine login also needs its code.
POST /v1/machine-logins/lookup Dispatch token Find a pending machine login by the confirmation code its machine shows.
GET /v1/launcher-credentials Dispatch token List the machine logins the named person may revoke, every service’s, such as the Legion daemon’s, whoever approved it, and the person’s own machines’, that are not revoked and are unexpired or expired with a session still running, each naming who approved it.
POST /v1/launcher-credentials/{id}/revoke-by-approver Dispatch token End a machine login, expired or not: a service’s (its token login, or one a person approved before token logins) as anyone signed in, a person’s machine’s as the person who approved it. Its launcher proofs stop authenticating and every session it enrolled, pods included, ends with its grants and pending requests.
GET /v1/grants Dispatch token List the live grants of the named person’s sessions, automatic or approved, and those the person approved.
POST /v1/grants/{id}/revoke-by-approver Dispatch token End a grant as its approver or as its enrollment’s operator. The operator’s revoke also withholds the secrets the grant’s request got automatically from that session, even when the grant had already ended: its other grants that got them automatically end too, and it asks before it gets them again.
GET /v1/operator/machines Machine credential List the logins of the calling credential’s operator’s own machines, as Dispatch’s machine-logins page lists them, without the service logins that page also lists.
POST /v1/operator/machines/{id}/revoke Machine credential End one of the operator’s own machines’ logins: no proof signed with it authenticates again and every session it enrolled ends. A service’s login is not found here, like an unknown id. Revoking the calling machine’s own login ends this machine’s access.
GET /v1/operator/grants Machine credential List the live grants of the operator’s sessions and those the operator approved, exactly as Dispatch’s Live grants page lists them.
POST /v1/operator/grants/{id}/revoke Machine credential End a grant as the operator: the revocation Dispatch’s page offers, which also withholds an automatic grant’s secrets from its session.
GET /v1/settings None The namespace prefix, AWS account and region, and the agent-secrets key the broker serves: what the CLI needs so it and the broker never disagree about which secret a name means.
POST /v1/secrets/{name}/reread None Reread one secret from Secrets Manager now, as whoever just wrote it may ask: the change is served, or gone, within seconds instead of at the next five-minute reload. Open to any caller, and rate-limited both per source address and over every caller at once, since each reread holds the policy’s writer lock while it reads; a reread only moves the broker toward AWS’s own truth.
GET /healthz None Report whether the broker can reach its database.

Enroll a session’s or pod’s signing key under the caller’s machine credential.

  • Credential: Machine credential
  • Success: 200, 201
  • Source: packages/envoy/internal/broker/api/handlers_enroll.go:95

Request body (JSON):

Field Type Description
kind string What the session is: “session” (an agent session on a machine its person logged in) or “pod”. The broker also takes “host” and “box” and records either as “session” (legacyKinds).
runtime_id string The session’s runtime: a pod’s UID, or whatever names the session on its machine (the helper’s host:pid:start time, a container’s id). A launcher enrolls one live session per runtime id (and slot).
slot string A pod only, optional: which of the pod’s independent enrollments this is.
operator string or null Optional: the operator the session runs for. The broker records the machine credential’s own operator whatever is sent, and refuses any other login. Absent or null for a pod.
thumbprint string The RFC 7638 JWK thumbprint of the session’s P-256 signing key.
session_id string or null Optional: the Envoy session the broker notifies when one of this session’s pending requests expires.
pod_token string or null A pod only: its projected service-account token, which proves the runtime id is its UID.

Response body (JSON):

Field Type Description
enrollment_id string The enrollment’s id, which the session’s Proof headers name.
lease_expires_at string (RFC 3339 time) When the enrollment’s lease lapses unless the session renews it.
slot string or null The pod slot it holds; null for every enrollment without one.

Refusals:

Status Code Message
409 ALREADY_ENROLLED this runtime is already enrolled and live
500 INTERNAL create enrollment failed
400 INVALID_ENROLLMENT body must be one valid JSON object: (varies)
400 INVALID_KIND kind must be “session” or “pod”
400 INVALID_SLOT a slot is only for a pod enrollment and must match ^[a-z][a-z0-9-]{0,62}$
401 LAUNCHER_INVALID the launcher credential is not valid
403 OPERATOR_MISMATCH this launcher credential enrols a different operator
403 POD_IDENTITY_MISMATCH the projected token does not identify this pod
403 POD_TOKEN_EXPIRED the projected token has expired
413 REQUEST_TOO_LARGE request body exceeds … bytes

Revoke an enrollment made under the caller’s machine credential’s operator, or a pod enrollment the caller’s own machine credential made.

  • Credential: Machine credential
  • Path parameters: id
  • Success: 204, with no body
  • Source: packages/envoy/internal/broker/api/handlers_enroll.go:166

Refusals:

Status Code Message
400 ENROLLMENT_ID_INPUT enrollment ids are UUIDs
500 INTERNAL revoke enrollment failed
403 NOT_ENROLLING_CREDENTIAL only the machine login that enrolled a pod may end its enrollment
403 OPERATOR_MISMATCH this launcher credential enrols a different operator

Start a person’s machine login: answers the confirmation code they type and a pending id.

  • Credential: None
  • Success: 202
  • Source: packages/envoy/internal/broker/api/handlers_launcher.go:47

Request body (JSON):

Field Type Description
request string The machine’s signed login request: a compact ES256 JWS carrying the machine’s new public key, signed with that key. A person’s machine login names that person in its login_hint, and only they approve it.

Response body (JSON):

Field Type Description
pending_id string The opaque id the machine polls the login by; only the machine knows it.
code string The XXXX-XXXX confirmation code the machine shows and the approver types into Dispatch.

Refusals:

Status Code Message
500 INTERNAL machine login failed
400 INVALID_REQUEST body must be one valid JSON object: (varies)
429 RATE_LIMITED too many launcher credential requests; try again later
400 REQUEST_INVALID (varies)
request object invalid
413 REQUEST_TOO_LARGE request body exceeds … bytes
400 SERVICE_LOGS_IN_WITH_TOKEN (varies)
a service logs in with its own Kubernetes ServiceAccount token at POST /v1/launcher-credentials/token, never through a code a person approves

Log a service in with its own Kubernetes ServiceAccount token, which no person approves: answers its launcher credential’s id and expiry.

  • Credential: None
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_launcher.go:140

Request body (JSON):

Field Type Description
token string The service’s projected Kubernetes ServiceAccount token, whose audience is the broker’s (BROKER_K8S_OIDC_AUDIENCE) and whose account BROKER_SERVICE_LOGINS names.
request string A machine request object signed by the key the credential is bound to: a compact ES256 JWS carrying that public key, with one launcher_credential detail naming the account’s service.

Response body (JSON):

Field Type Description
credential_id string The launcher credential’s id, which every launcher proof the key signs names.
expires_at string (RFC 3339 time) When the credential expires: the token’s own expiry, at most an hour after the login. The service logs in again before then with its current token, and no person approves it.

Refusals:

Status Code Message
403 ACCOUNT_NOT_LISTED this ServiceAccount does not log in as this service
500 INTERNAL token login failed
400 INVALID_REQUEST body must be one valid JSON object: (varies)
409 KEY_HOLDS_LIVE_CREDENTIAL this machine login’s key already holds a live launcher credential
429 RATE_LIMITED too many launcher credential requests; try again later
too many token logins for this ServiceAccount; try again later
400 REQUEST_INVALID request object invalid
413 REQUEST_TOO_LARGE request body exceeds … bytes
401 TOKEN_EXPIRED the ServiceAccount token has expired
401 TOKEN_INVALID the ServiceAccount token does not verify
404 TOKEN_LOGIN_OFF this broker trusts no Kubernetes token issuer, so no service logs in with a token
401 TOKEN_TOO_LONG_LIVED the ServiceAccount token lives longer than an hour from its issue

Poll a machine login by its pending id; once approved, answers its credential’s id.

  • Credential: None
  • Path parameters: pending
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_launcher.go:89

Response body (JSON):

Field Type Description
credential_id string or absent Once the login is approved, the minted machine credential’s id; absent before then.
expires_at string (RFC 3339 time) or null or absent Once the login is approved, the moment the minted credential expires; absent before then. Renewing it takes a new machine login a human approves.
state string “pending”, “issued” (approved), “denied” or “expired”.

Refusals:

Status Code Message
500 INTERNAL read machine login failed
404 NOT_FOUND no such pending machine login

Extend the calling session’s lease.

  • Credential: Renewal session proof
  • Path parameters: id
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_enroll.go:193

Request body (JSON):

Field Type Description
pod_token string or null A pod only: its current projected service-account token, which must name the pod UID and service account the enrollment was made for. Required once the enrollment has renewed with it (enroll.Service.Renew).

Response body (JSON):

Field Type Description
lease_expires_at string (RFC 3339 time) When the renewed lease lapses.

Refusals:

Status Code Message
400 ENROLLMENT_ID_INPUT enrollment ids are UUIDs
401 ENROLLMENT_NOT_LIVE enrollment is not live
500 INTERNAL renew enrollment failed
400 INVALID_RENEWAL body must be one valid JSON object: (varies)
403 NOT_YOURS a session may only renew its own enrollment
403 POD_IDENTITY_MISMATCH the projected token does not identify this pod
403 POD_TOKEN_EXPIRED the projected token has expired
403 POD_TOKEN_REQUIRED a pod enrollment’s renewal must carry its projected token
413 REQUEST_TOO_LARGE request body exceeds … bytes

Describe the calling session’s enrollment and its live grants.

  • Credential: Session proof
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_enroll.go:231

Response body (JSON):

Field Type Description
enrollment_id string The session’s enrollment id.
grants array of objects The session’s live grants, soonest to expire first.
kind string “session” or “pod”.
lease_expires_at string (RFC 3339 time) When the session’s lease lapses unless it is renewed.
operator string or null The person the session runs for; null for a pod.
slot string or null The pod slot it holds; null for every enrollment without one.

Fields of grants[]:

Field Type Description
grant_id string The grant’s id, which the values and revoke routes take.
request_id string The request it answered.
approver string or null The login that approved it; null for a grant the policy gave automatically.
expires_at string (RFC 3339 time) or null When it expires; null for a grant that lasts until its session ends.

Refusals:

Status Code Message
500 INTERNAL read enrollment failed
read live grants failed
401 PROOF_INVALID enrollment is not live

Request secrets: the policy grants or denies them at once, or a person must approve them.

  • Credential: Session proof
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_requests.go:61

Request body (JSON):

Field Type Description
request string The session’s signed request: a compact ES256 JWS, signed with the session’s key and addressed to the broker’s public URL, naming the secrets (authorization_details) and the reason.
session_id string or null Optional: the Envoy session the broker notifies if this request expires undecided.

Response body (JSON):

Field Type Description
request_id string The request’s id, which GET /v1/requests/{id} and its cancel route take.
state string “granted”, “pending” (a person must decide it) or “denied”.
secrets array of objects How the policy decided each name asked for.
grant_id string or null Once granted, the grant to read the values from; null otherwise.
record_id string or null The credential-request record the approver decides; null when nobody needs to.
approver string or null Who decides it, as its record names them: a person’s Dispatch login (their lowercase email), or “anyone” for a shared secret, which anyone signed in to Dispatch may decide. While it is pending it waits in that person’s Dispatch Inbox, or in everyone’s for “anyone”. Null when the policy decided it at once, so no record names one.
lifetime_seconds number or null How many seconds its grant lasts, as the signed request asked; null when it asked for no lifetime, and the grant lasts until the session ends. A reused or coalesced request answers its own, which equals the one asked for. A client that asked for a lifetime and reads null, or no such field from a broker before it, was not given that lifetime.
coalesced boolean or absent True when the request joined an identical one this session already had pending.

Fields of secrets[]:

Field Type Description
name string The secret’s name.
decision string “automatic”, “approval” or “deny”.

Refusals:

Status Code Message
500 INTERNAL create request failed
400 INVALID_REQUEST body must be one valid JSON object: (varies)
400 MIXED_APPROVERS the requested secrets need different approvers; request them separately
401 PROOF_INVALID enrollment is not live
400 REQUEST_INVALID request object invalid
409 REQUEST_PENDING a request for one or more of these secrets is already pending
413 REQUEST_TOO_LARGE request body exceeds … bytes
400 SESSION_ID_INPUT session id must be at most 128 characters with no whitespace or control character
400 UNKNOWN_SECRET no agent secret has this name

Read one of the calling session’s requests.

  • Credential: Session proof
  • Path parameters: id
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_requests.go:149

Response body (JSON):

Field Type Description
state string “pending”, “granted”, “denied”, “expired” or “cancelled”.
grant_id string or null Once granted, the grant to read the values from; null otherwise.
record_id string or null The credential-request record the approver decides; null when nobody needs to.
approver string or null Who decides it, as its record names them: a person’s Dispatch login (their lowercase email), or “anyone” for a shared secret, which anyone signed in to Dispatch may decide. The record fixes it when the request is made, so a later change to the secret’s owner does not move it, and it stays once the request is decided. Null when the policy decided it at once, so no record names one.
lifetime_seconds number or null How many seconds its grant lasts, as the signed request asked; null for a grant that lasts until the session ends.
decided_at string (RFC 3339 time) or null When it left “pending”; null while pending.
decision object or null Who decided it and when; null while pending, when the policy decided it at once, and when it expired.

Fields of decision:

Field Type Description
by string Who decided it: the approver’s login, “session:<enrollment id>” (the session cancelled it), “launcher:<credential id>” (its launcher ended the session, or its operator ended its machine login from one of their machines) or “broker” (the session’s lease lapsed).
at string (RFC 3339 time) When it was decided.

Refusals:

Status Code Message
500 INTERNAL read request failed
read request owner failed
404 NOT_FOUND no such request
403 NOT_YOURS this request belongs to another session
400 REQUEST_ID_INPUT request ids are UUIDs

Cancel one of the calling session’s pending requests.

  • Credential: Session proof
  • Path parameters: id
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_requests.go:181

Response body (JSON):

Field Type Description
state string The state the call left the request, record or grant in: “denied”, “cancelled” or “revoked”.

Refusals:

Status Code Message
500 INTERNAL cancel request failed
404 NOT_FOUND no such request
403 NOT_YOURS this request or grant belongs to another session
400 REQUEST_ID_INPUT request ids are UUIDs
409 REQUEST_TERMINAL request is already decided

Release a live grant’s values to the session that holds it.

  • Credential: Session proof
  • Path parameters: id
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_requests.go:204

Response body (JSON):

Field Type Description
expires_at string (RFC 3339 time) or null When the grant expires; the session can read the values again until then. Null for a grant that lasts until the session ends.
values object of string values Each granted name’s value, read fresh from the secret store.

Refusals:

Status Code Message
403 GRANT_CHAIN_INVALID this grant’s approval chain no longer verifies
400 GRANT_ID_INPUT grant ids are UUIDs
403 GRANT_NOT_LIVE grant is expired, revoked, or its session ended
500 INTERNAL read grant values failed
403 NOT_YOURS this request or grant belongs to another session
404 SECRET_NOT_IN_STORE secret is not in the secrets store

End a grant the calling session holds.

  • Credential: Session proof
  • Path parameters: id
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_requests.go:236

Response body (JSON):

Field Type Description
state string The state the call left the request, record or grant in: “denied”, “cancelled” or “revoked”.

Refusals:

Status Code Message
400 GRANT_ID_INPUT grant ids are UUIDs
500 INTERNAL revoke grant failed
404 NOT_FOUND no such grant
403 NOT_YOURS this request or grant belongs to another session

List the pending requests and machine logins the named person decides.

  • Credential: Dispatch token
  • Query parameters: approver
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_ui_pending.go:31

Response body (JSON):

Field Type Description
pending array of objects The undecided records the named person decides, newest first.

Fields of pending[]:

Field Type Description
record_id string The credential-request record’s id, which the record, approve and deny routes take.
kind string “agent_secret” (a secret request) or “launcher_credential” (a machine login).
identifiers array of strings The secrets a secret request asks for, or the machine a machine login names.
requested_at string (RFC 3339 time) When it was asked.
session object The session this request names, read independently of each other (LEGION-587); see recordSessionResp (handlers_ui_records.go), this row’s exact shape here too.

Fields of pending[].session:

Field Type Description
request string or null The id the request itself stated as an unsigned override in its body; null when it named none.
enrollment string or null The id the requesting session’s own enrollment stated when it enrolled; null when it named none, or for a machine login, which has no requesting enrollment at all.

Refusals:

Status Code Message
400 APPROVER_REQUIRED approver is required
500 INTERNAL list pending requests failed

Read a credential-request record: what was asked, by whom, why, and its decision.

  • Credential: Dispatch token
  • Path parameters: record
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_ui_records.go:131

Response body (JSON):

Field Type Description
record_id string The record’s id: the SHA-256 of its text.
kind string “agent_secret” (a secret request) or “launcher_credential” (a machine login).
state string “pending”, or how it ended: “approved”, “denied”, “expired”, “cancelled” or “revoked”.
approver string The one login that may decide it, or “anyone”: any signed-in person may decide a request for a shared human-tier secret, and may deny a service’s machine login (which only a broker before token logins opened, and which nobody approves any more), whatever person it names.
enrollment object or null The session asking; null for a machine login.
session object The session this record names, read independently of each other; null fields where that id was never set (LEGION-587).
identifiers array of strings The secrets asked for, or the machine logging in.
service string or null The service a machine login is for, when it logs a service in rather than a person’s machine; null otherwise.
reason string The reason the session gave, verbatim.
lifetime_seconds number or null How many seconds the grant or credential lasts once approved; null for a grant that lasts until its session ends. A machine login’s credential always names one.
rules_version string The version of the secret policy it was decided under (the SHA-256 of every agent secret’s name, owner, tier and ARN); for a machine login, the version current when it was asked.
expires_at string (RFC 3339 time) When it expires undecided.
requested_at string (RFC 3339 time) When it was asked.
decided object or null How it was decided; null while pending.

Fields of enrollment:

Field Type Description
kind string “session” (an agent session on a machine its person logged in) or “pod”.
runtime_id string The session’s runtime: whatever names the session on its machine (the helper’s host:pid:start time, a container’s id), or a pod’s UID.
operator string The person the session runs for; empty for a pod.
slot string or null The pod slot it holds; null for every enrollment without one.

Fields of session:

Field Type Description
request string or null The id the request itself stated as an unsigned override in its body; null when it named none.
enrollment string or null The id the requesting session’s own enrollment stated when it enrolled; null when it named none, or for a machine login, which has no requesting enrollment at all.

Fields of decided:

Field Type Description
event string “approved”, “denied”, “expired” or “cancelled”.
at string (RFC 3339 time) When it was decided.
credential_id string or null The machine credential an approved machine login minted; null otherwise.

Refusals:

Status Code Message
500 INTERNAL read credential request failed
404 NOT_FOUND no such credential request
400 RECORD_ID_INPUT record ids are lowercase-hex sha256 hashes

POST /v1/credential-requests/{record}/approve

Section titled “POST /v1/credential-requests/{record}/approve”

Approve a pending record as the named person; a machine login also needs its code.

  • Credential: Dispatch token
  • Path parameters: record
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_ui_records.go:171

Request body (JSON):

Field Type Description
approver string The Dispatch login of the person deciding, which the record’s rule must admit: its approver, or anyone signed in for a shared secret’s request or the denial of a service’s machine login.
code string or null A machine login only: its confirmation code, typed again; ignored for a secret request.

Response body (JSON):

Field Type Description
credential_id string or null The machine credential an approved machine login minted; null for a secret request.
grant_id string or null The grant an approved secret request made; null for a machine login.
state string “approved”.

Refusals:

Status Code Message
400 APPROVER_REQUIRED approver is required
403 CODE_MISMATCH confirmation code does not match
400 CODE_REQUIRED code is required to decide a machine login
403 GRANT_CHAIN_INVALID this grant’s approval chain no longer verifies
500 INTERNAL decide credential request failed
decide machine login failed
read credential request kind failed
400 INVALID_DECISION body must be one valid JSON object: (varies)
409 KEY_HOLDS_LIVE_CREDENTIAL this machine login’s key already holds a live launcher credential
403 NOT_APPROVER only the record’s approver may decide it
404 NOT_FOUND no such credential request
400 RECORD_ID_INPUT record ids are lowercase-hex sha256 hashes
409 RECORD_TERMINAL request expired before its approver acted on it
request is already decided
this machine login expired before its approver acted on it
this machine login has already been decided
413 REQUEST_TOO_LARGE request body exceeds … bytes
400 SERVICE_LOGS_IN_WITH_TOKEN a service logs in with its own Kubernetes ServiceAccount token at POST /v1/launcher-credentials/token, never through a code a person approves

POST /v1/credential-requests/{record}/deny

Section titled “POST /v1/credential-requests/{record}/deny”

Deny a pending record as the named person; a machine login also needs its code.

  • Credential: Dispatch token
  • Path parameters: record
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_ui_records.go:172

Request body (JSON):

Field Type Description
approver string The Dispatch login of the person deciding, which the record’s rule must admit: its approver, or anyone signed in for a shared secret’s request or the denial of a service’s machine login.
code string or null A machine login only: its confirmation code, typed again; ignored for a secret request.

Response body (JSON):

Field Type Description
state string The state the call left the request, record or grant in: “denied”, “cancelled” or “revoked”.

Refusals:

Status Code Message
400 APPROVER_REQUIRED approver is required
403 CODE_MISMATCH confirmation code does not match
400 CODE_REQUIRED code is required to decide a machine login
403 GRANT_CHAIN_INVALID this grant’s approval chain no longer verifies
500 INTERNAL decide credential request failed
decide machine login failed
read credential request kind failed
400 INVALID_DECISION body must be one valid JSON object: (varies)
409 KEY_HOLDS_LIVE_CREDENTIAL this machine login’s key already holds a live launcher credential
403 NOT_APPROVER only the record’s approver may decide it
404 NOT_FOUND no such credential request
400 RECORD_ID_INPUT record ids are lowercase-hex sha256 hashes
409 RECORD_TERMINAL request expired before its approver acted on it
request is already decided
this machine login expired before its approver acted on it
this machine login has already been decided
413 REQUEST_TOO_LARGE request body exceeds … bytes
400 SERVICE_LOGS_IN_WITH_TOKEN a service logs in with its own Kubernetes ServiceAccount token at POST /v1/launcher-credentials/token, never through a code a person approves

Find a pending machine login by the confirmation code its machine shows.

  • Credential: Dispatch token
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_ui_machinelogin.go:28

Request body (JSON):

Field Type Description
code string The XXXX-XXXX confirmation code the machine shows, as the approver typed it.

Response body (JSON):

Field Type Description
record_id string The record’s id: the SHA-256 of its text.
kind string “agent_secret” (a secret request) or “launcher_credential” (a machine login).
state string “pending”, or how it ended: “approved”, “denied”, “expired”, “cancelled” or “revoked”.
approver string The one login that may decide it, or “anyone”: any signed-in person may decide a request for a shared human-tier secret, and may deny a service’s machine login (which only a broker before token logins opened, and which nobody approves any more), whatever person it names.
enrollment object or null The session asking; null for a machine login.
session object The session this record names, read independently of each other; null fields where that id was never set (LEGION-587).
identifiers array of strings The secrets asked for, or the machine logging in.
service string or null The service a machine login is for, when it logs a service in rather than a person’s machine; null otherwise.
reason string The reason the session gave, verbatim.
lifetime_seconds number or null How many seconds the grant or credential lasts once approved; null for a grant that lasts until its session ends. A machine login’s credential always names one.
rules_version string The version of the secret policy it was decided under (the SHA-256 of every agent secret’s name, owner, tier and ARN); for a machine login, the version current when it was asked.
expires_at string (RFC 3339 time) When it expires undecided.
requested_at string (RFC 3339 time) When it was asked.
decided object or null How it was decided; null while pending.

Fields of enrollment:

Field Type Description
kind string “session” (an agent session on a machine its person logged in) or “pod”.
runtime_id string The session’s runtime: whatever names the session on its machine (the helper’s host:pid:start time, a container’s id), or a pod’s UID.
operator string The person the session runs for; empty for a pod.
slot string or null The pod slot it holds; null for every enrollment without one.

Fields of session:

Field Type Description
request string or null The id the request itself stated as an unsigned override in its body; null when it named none.
enrollment string or null The id the requesting session’s own enrollment stated when it enrolled; null when it named none, or for a machine login, which has no requesting enrollment at all.

Fields of decided:

Field Type Description
event string “approved”, “denied”, “expired” or “cancelled”.
at string (RFC 3339 time) When it was decided.
credential_id string or null The machine credential an approved machine login minted; null otherwise.

Refusals:

Status Code Message
400 CODE_REQUIRED code is required
500 INTERNAL lookup machine login failed
read credential request failed
400 INVALID_LOOKUP body must be one valid JSON object: (varies)
404 NO_SUCH_CODE no pending machine login has this code
413 REQUEST_TOO_LARGE request body exceeds … bytes

List the machine logins the named person may revoke, every service’s, such as the Legion daemon’s, whoever approved it, and the person’s own machines’, that are not revoked and are unexpired or expired with a session still running, each naming who approved it.

  • Credential: Dispatch token
  • Query parameters: approver
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_ui_machinelogin.go:92

Response body (JSON):

Field Type Description
credentials array of objects The machine logins that are not revoked and are either unexpired or expired with a session still running, newest first: every service’s and the named person’s own machines’ on Dispatch’s page, the calling operator’s own machines’ alone on the operator route.

Fields of credentials[]:

Field Type Description
credential_id string The launcher credential’s id, which the revoke route takes.
host string The machine’s host name, as a person’s machine login named it; for a service’s token login, its ServiceAccount’s <namespace>/<name>.
service string or null The service a service’s login is for (legion-daemon), whose sessions are its pods; null for a person’s own machine.
subject string or null The ServiceAccount a service’s token login proved (system:serviceaccount:<namespace>:<name>); null for every login a person approved.
approved_by string The login of the person who approved the login (anyone signed in may have approved a service’s login before token logins); “” for a service’s token login, which no person approves.
issued_at string (RFC 3339 time) When the login was approved, or a token login’s first login.
expires_at string (RFC 3339 time) When the credential expires. A person’s machine login does not renew; a token login moves it later at each login, at most an hour away.
expired boolean True once expires_at has passed: the login enrolls nothing more, but sessions it enrolled still run (each renews with its own key), and revoking it ends them.

Refusals:

Status Code Message
400 APPROVER_REQUIRED approver is required
500 INTERNAL list launcher credentials failed

POST /v1/launcher-credentials/{id}/revoke-by-approver

Section titled “POST /v1/launcher-credentials/{id}/revoke-by-approver”

End a machine login, expired or not: a service’s (its token login, or one a person approved before token logins) as anyone signed in, a person’s machine’s as the person who approved it. Its launcher proofs stop authenticating and every session it enrolled, pods included, ends with its grants and pending requests.

  • Credential: Dispatch token
  • Path parameters: id
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_ui_machinelogin.go:122

Request body (JSON):

Field Type Description
approver string The Dispatch login of the person revoking: for a grant, its approver or its session’s operator; for a person’s machine login, the person who approved it; for a service’s machine login, anyone signed in.

Response body (JSON):

Field Type Description
state string The state the call left the request, record or grant in: “denied”, “cancelled” or “revoked”.

Refusals:

Status Code Message
400 APPROVER_REQUIRED approver is required
400 CREDENTIAL_ID_INPUT launcher credential ids are UUIDs
500 INTERNAL revoke launcher credential failed
400 INVALID_REVOKE body must be one valid JSON object: (varies)
403 NOT_APPROVER only the person who approved a person’s machine login may revoke it
404 NOT_FOUND no such machine login
413 REQUEST_TOO_LARGE request body exceeds … bytes

List the live grants of the named person’s sessions, automatic or approved, and those the person approved.

  • Credential: Dispatch token
  • Query parameters: approver
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_ui_grants.go:45

Response body (JSON):

Field Type Description
grants array of objects The live grants of the named person’s sessions, and those the person approved, newest first.

Fields of grants[]:

Field Type Description
grant_id string The grant’s id, which the revoke route takes.
granted string How the session got it: “automatic” (the policy gave it without asking) or “approval”.
record_id string or null The credential-request record its approval rests on; null for an automatic grant.
enrollment object The session holding it.
names array of strings The secrets it covers.
approver string or null The person who approved it; null for an automatic grant.
expires_at string (RFC 3339 time) or null When it expires; null for a grant that lasts until its session ends.
created_at string (RFC 3339 time) When it was granted.

Fields of grants[].enrollment:

Field Type Description
kind string “session” (an agent session on a machine its person logged in) or “pod”.
runtime_id string The session’s runtime: whatever names the session on its machine (the helper’s host:pid:start time, a container’s id), or a pod’s UID.
operator string The person the session runs for; empty for a pod.
slot string or null The pod slot it holds; null for every enrollment without one.

Refusals:

Status Code Message
400 APPROVER_REQUIRED approver is required
500 INTERNAL list grants for approver failed

End a grant as its approver or as its enrollment’s operator. The operator’s revoke also withholds the secrets the grant’s request got automatically from that session, even when the grant had already ended: its other grants that got them automatically end too, and it asks before it gets them again.

  • Credential: Dispatch token
  • Path parameters: id
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_ui_grants.go:89

Request body (JSON):

Field Type Description
approver string The Dispatch login of the person revoking: for a grant, its approver or its session’s operator; for a person’s machine login, the person who approved it; for a service’s machine login, anyone signed in.

Response body (JSON):

Field Type Description
state string The state the call left the request, record or grant in: “denied”, “cancelled” or “revoked”.

Refusals:

Status Code Message
400 APPROVER_REQUIRED approver is required
400 GRANT_ID_INPUT grant ids are UUIDs
500 INTERNAL revoke grant failed
400 INVALID_REVOKE body must be one valid JSON object: (varies)
403 NOT_APPROVER only the grant’s approver or its enrollment’s operator may revoke it
404 NOT_FOUND no such grant
413 REQUEST_TOO_LARGE request body exceeds … bytes

List the logins of the calling credential’s operator’s own machines, as Dispatch’s machine-logins page lists them, without the service logins that page also lists.

  • Credential: Machine credential
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_operator.go:31

Response body (JSON):

Field Type Description
credentials array of objects The machine logins that are not revoked and are either unexpired or expired with a session still running, newest first: every service’s and the named person’s own machines’ on Dispatch’s page, the calling operator’s own machines’ alone on the operator route.

Fields of credentials[]:

Field Type Description
credential_id string The launcher credential’s id, which the revoke route takes.
host string The machine’s host name, as a person’s machine login named it; for a service’s token login, its ServiceAccount’s <namespace>/<name>.
service string or null The service a service’s login is for (legion-daemon), whose sessions are its pods; null for a person’s own machine.
subject string or null The ServiceAccount a service’s token login proved (system:serviceaccount:<namespace>:<name>); null for every login a person approved.
approved_by string The login of the person who approved the login (anyone signed in may have approved a service’s login before token logins); “” for a service’s token login, which no person approves.
issued_at string (RFC 3339 time) When the login was approved, or a token login’s first login.
expires_at string (RFC 3339 time) When the credential expires. A person’s machine login does not renew; a token login moves it later at each login, at most an hour away.
expired boolean True once expires_at has passed: the login enrolls nothing more, but sessions it enrolled still run (each renews with its own key), and revoking it ends them.

Refusals:

Status Code Message
500 INTERNAL list launcher credentials failed
403 SERVICE_CREDENTIAL a service’s machine login has no operator; machine and grant commands are a person’s

End one of the operator’s own machines’ logins: no proof signed with it authenticates again and every session it enrolled ends. A service’s login is not found here, like an unknown id. Revoking the calling machine’s own login ends this machine’s access.

  • Credential: Machine credential
  • Path parameters: id
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_operator.go:43

Response body (JSON):

Field Type Description
state string The state the call left the request, record or grant in: “denied”, “cancelled” or “revoked”.

Refusals:

Status Code Message
400 CREDENTIAL_ID_INPUT launcher credential ids are UUIDs
500 INTERNAL revoke launcher credential failed
403 NOT_APPROVER only the person who approved a person’s machine login may revoke it
404 NOT_FOUND no such machine login
403 SERVICE_CREDENTIAL a service’s machine login has no operator; machine and grant commands are a person’s

List the live grants of the operator’s sessions and those the operator approved, exactly as Dispatch’s Live grants page lists them.

  • Credential: Machine credential
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_operator.go:57

Response body (JSON):

Field Type Description
grants array of objects The live grants of the named person’s sessions, and those the person approved, newest first.

Fields of grants[]:

Field Type Description
grant_id string The grant’s id, which the revoke route takes.
granted string How the session got it: “automatic” (the policy gave it without asking) or “approval”.
record_id string or null The credential-request record its approval rests on; null for an automatic grant.
enrollment object The session holding it.
names array of strings The secrets it covers.
approver string or null The person who approved it; null for an automatic grant.
expires_at string (RFC 3339 time) or null When it expires; null for a grant that lasts until its session ends.
created_at string (RFC 3339 time) When it was granted.

Fields of grants[].enrollment:

Field Type Description
kind string “session” (an agent session on a machine its person logged in) or “pod”.
runtime_id string The session’s runtime: whatever names the session on its machine (the helper’s host:pid:start time, a container’s id), or a pod’s UID.
operator string The person the session runs for; empty for a pod.
slot string or null The pod slot it holds; null for every enrollment without one.

Refusals:

Status Code Message
500 INTERNAL list grants for approver failed
403 SERVICE_CREDENTIAL a service’s machine login has no operator; machine and grant commands are a person’s

End a grant as the operator: the revocation Dispatch’s page offers, which also withholds an automatic grant’s secrets from its session.

  • Credential: Machine credential
  • Path parameters: id
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_operator.go:69

Response body (JSON):

Field Type Description
state string The state the call left the request, record or grant in: “denied”, “cancelled” or “revoked”.

Refusals:

Status Code Message
400 GRANT_ID_INPUT grant ids are UUIDs
500 INTERNAL revoke grant failed
403 NOT_APPROVER only the grant’s approver or its enrollment’s operator may revoke it
404 NOT_FOUND no such grant
403 SERVICE_CREDENTIAL a service’s machine login has no operator; machine and grant commands are a person’s

The namespace prefix, AWS account and region, and the agent-secrets key the broker serves: what the CLI needs so it and the broker never disagree about which secret a name means.

  • Credential: None
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_secrets.go:40

Response body (JSON):

Field Type Description
store string Which secret store holds the agent secrets: aws-secrets-manager or gcp-secret-manager. A broker from before this field answered none, and held them in AWS Secrets Manager.
secrets_prefix string The name prefix every agent secret sits under: with aws-secrets-manager a Secrets Manager name prefix ending in “/”, with gcp-secret-manager projects/<project number>/secrets/<secret-id prefix>-. The secret a session asks for as DEEL_API_KEY is <prefix>deel-api-key.
kms_key_arn string or absent With aws-secrets-manager, the ARN of the agent-secrets KMS key, which every agent secret must be encrypted with; absent otherwise.
aws_account_id string or absent With aws-secrets-manager, the AWS account the agent-secrets key, and so every agent secret, is in; absent otherwise.
aws_region string or absent With aws-secrets-manager, the AWS region the agent-secrets key, and so every agent secret, is in; absent otherwise.
kms_key_name string or absent With gcp-secret-manager, the resource name of the agent-secrets Cloud KMS key, which every agent secret must be encrypted with; absent otherwise.
gcp_project string or absent With gcp-secret-manager, the number of the project every agent secret is in, the one the prefix names; absent otherwise.

Reread one secret from Secrets Manager now, as whoever just wrote it may ask: the change is served, or gone, within seconds instead of at the next five-minute reload. Open to any caller, and rate-limited both per source address and over every caller at once, since each reread holds the policy’s writer lock while it reads; a reread only moves the broker toward AWS’s own truth.

  • Credential: None
  • Path parameters: name
  • Success: 200
  • Source: packages/envoy/internal/broker/api/handlers_secrets.go:72

Response body (JSON):

Field Type Description
name string The name reread, as the path gave it.
served boolean True when the broker now serves the secret.
reason string or absent Why the broker does not serve it, absent when it does: “absent” (no secret under the prefix carries the name, or the one that does is scheduled for deletion) or the reason the broker refused the secret, the one its policy-refused log line names (such as owner-tag-missing or no-current-value).

Refusals:

Status Code Message
500 INTERNAL reread secret failed
429 RATE_LIMITED too many secret rereads; try again later
503 REQUEST_ENDED the request ended before the reread finished; send it again
400 SECRET_NAME_INVALID not an agent secret name

Report whether the broker can reach its database.

  • Credential: None
  • Success: 200
  • Source: packages/envoy/internal/broker/api/server.go:287

Response body (JSON):

Field Type Description
status string “ok”.

Refusals:

Status Code Message
503 DATABASE_UNAVAILABLE ping Postgres failed: a dependency the broker needs is unavailable