Skip to content

Roles

Role grants for delegated administration. Concepts and the enable/bootstrap walkthrough live in Delegated administration; the enforcement matrix is on each endpoint's own reference page.

While skills-gateway.roles.enabled=false (the default) these endpoints are open to any authenticated session and the grants they manage have no effect — staging data for the flip. Once enabled, all three are admin-only.

Machine reach. roles:read covers GET /roles. Granting and revoking are reachable by no scope at all: estate.grants already declares grants with no credential in the pipeline, so a machine write path would add escalation surface for something with a safer route.

Every authorized read of this endpoint is on the ledger

Reading who holds what authority has reconnaissance value to a stolen credential. Denying the read would not prevent configuration drift — the estate never prunes, so it cannot discover a grant made by hand — it would only make that drift undetectable, so the exposure is made visible after the fact instead. A person's read is recorded exactly as a machine's is; the entry's actor type is what separates them. A refused read records nothing.


GET /api/roles

List every current grant.

$ curl localhost:8080/api/roles
[{"id":1,"principal":"alice@example.com","role":"approver","marketplace":"acme",
  "grantedBy":"admin@example.com","grantedAt":"2026-08-17T09:00:00Z"},
 {"id":2,"principal":"carol@example.com","role":"auditor","marketplace":null,
  "grantedBy":"admin@example.com","grantedAt":"2026-08-17T09:01:00Z"}]

Configuration-bootstrapped admins and roles derived from identity-provider claims are not grants and do not appear here; they show as effective roles with source config and claim on /api/me.

Status Meaning
200 The current grants.
403 Enforcement is enabled and the caller is not an admin.

POST /api/roles

Grant a role.

$ curl -X POST localhost:8080/api/roles \
    -H 'Content-Type: application/json' \
    -d '{"principal": "alice@example.com", "role": "approver", "marketplace": "acme"}'
Field Required Notes
principal yes The identity as the OIDC session reports it.
role yes admin, approver, or auditor.
marketplace for approver Must exist at grant time. Forbidden for admin and auditor.
Status Meaning
201 Granted; the grant is on the ledger as role-granted.
403 Enforcement is enabled and the caller is not an admin.
404 An approver grant named a marketplace that does not exist.
409 The identical grant already exists.
422 Missing principal, unknown role, approver without a marketplace, or a global role with one.

DELETE /api/roles/{id}

Revoke a grant. The row is deleted; the ledger keeps the history as role-revoked.

Status Meaning
204 Revoked.
403 Enforcement is enabled and the caller is not an admin.
404 No such grant.

Configuration admins cannot be revoked here

Principals in skills-gateway.roles.admins have no grant row — there is nothing this endpoint could delete. Removing one is a configuration change, by design: the bootstrap list is the escape hatch that survives a bad grant edit.