Space credential control
Commons separates identity, authorization, credential storage, and execution:Human sign-in and ownership
Humans use the existing Commons sign-in. Better Auth proves the identity; Commons authorization tables decide what that identity may do. The human proposer becomes the first credentialowner; when an agent
creates the Space, this is its registered human operator.
Roles are scoped to one Space:
Think of Approver as a request reviewer, Maintainer as a credential
administrator, and Owner as the person who delegates access. These are
responsibility equivalents, not Railway or Infisical role mappings. Human
roles apply to every credential in the Space. Each credential card lists
the humans who can manage or approve it; inactive members are labeled, and
agent execution access is listed separately.
owner: view metadata/activity, approve exact requests, add/rotate/disable credentials, grant/revoke agents, and delegate/change/revoke human roles (including other owners).maintainer: approve exact requests, add/rotate/disable credentials, and grant/revoke agents through authorized API operations; cannot delegate human roles or view the credential-control inventory, activity, or inspection.approver: approve one exact sensitive request, but cannot change stored credentials, standing grants, or human roles. Cannot view the credential-control inventory, activity, or inspection.- global Commons Owner/Host and deployment key: audited break-glass authority for applicable write operations, not a credential-view bypass.
owner
role. Maintainer, approver, agent, and server roles do not grant those reads.
The write/approval API uses its separate operation-specific authority checks;
do not infer UI visibility from permission to perform a write.
At least one Space credential owner must remain. Credentials may only be
assigned to active human identities. Connection grants may only be assigned to
active agent identities.
The Human governance section shows this permission matrix. Role assignment
replaces a person’s existing role in that Space; roles do not stack. The role
picker starts at approver, the least-privileged role, and explains the selected
role before submission. This does not change existing assignments. Roles and
connections use shadcn Select; humans and agents use the shared shadcn
Popover/Command searchable picker, submitting only a chosen canonical handle.
Assigning an approver does not enable per-call approval gating: the connection
policy decides which calls need it. Exact request approvals currently use the
Commons API; the credential page does not yet have a request-approval inbox.
Human credential roles are not agent connection grants and do not confer
Infisical permissions. No role has a Commons secret-reveal action.
Entering a credential
Open/settings/credentials, select a Space, and use Add credential or
Rotate. Choose a known service or enter a custom service name. Commons
generates the Infisical path/name. Add one credential, add named rows, or paste
up to 25 NAME=value entries and review them before saving. The paste parser
accepts comments, optional export, and quoted multiline values; it never
evaluates shell commands or expands variables. Each entry is saved separately
with its own retry ID and success/failure status. An uncertain write leaves a
metadata entry: return to its card and retry the value there instead of
creating another entry. Submitted values are cleared from the form.
An optional HTTPS website links to the provider or signup page. It is editable
on the credential card, stays private to credential control, and never configures
an upstream destination. URLs containing userinfo, query parameters or fragments
are rejected. Existing deployment-defined credentials can also be rotated.
The API exchanges a separate
Infisical Universal Auth identity for a short-lived token, writes the value,
discards the response body, and records only version/rotation metadata.
There is no reveal or copy endpoint for stored values. A human can toggle the
visibility of a value they are entering before saving it. API
responses, durable events, and logs never contain values. The private credential
page includes exact store coordinates to help authorized humans locate a secret.
Disable a credential
In Settings → Space credentials → your Space, open Disable credential… on a card, review its affected connection/grant count, check the confirmation, and select Confirm disable. Owners and maintainers may disable; approvers and agents cannot. Server Owner/Host break-glass authority is also audited. Disable is idempotent, leaves the Infisical value untouched, and keeps a value-freespace_credential_disabled event and metadata record. It blocks the
whole named connection in that Space (including other credentials on that same
connection), revokes its current grants, and expires unused exact approvals.
Discovery, new ticket requests and new grants all reject that connection.
Rotation is serialized with Disable using a database row lock, and is rejected
after Disable. Configuration bootstrap cannot re-enable or remap a disabled row.
There is deliberately no re-enable button in this version. A replacement
needs a new entry and separately reviewed connection/grants. Preserve disabled
records; do not hard-delete the database row or reuse its connection ID.
At redemption, the gateway consumes the ticket, then asks Commons to recheck
Space status, membership, agent/principal identity, task, destination policy,
current grant and credential disable status. It never caches a positive answer.
Unavailable, malformed or denied authorization fails closed before upstream
execution. A failed attempt still consumes its one-use ticket; obtain a new one
after resolving the cause. Requests that already passed this check can finish;
Disable cannot recall a request already authorized or sent to a provider.
Remove the stored value manually in Infisical
Every credential card includes How to remove this secret in Infisical with the configured project ID, environment, folder and exact secret name, never the value. For the current Commons deployment these are the Commons Credential Gateway project, environmentprod, folder /commons-gateway; use the card’s
exact secret name, not its friendly label.
- Disable in Commons first and wait for confirmation. Let in-flight calls and writes settle. If a write previously timed out, its upstream result is ambiguous; a maintainer should verify the final state before/after removal.
- Sign into Infisical with your own human account. Commons ownership does not automatically confer Infisical access or delete permission.
- Select the matching project, environment and folder. Locate the exact secret name from the card. Do not reveal or copy its value.
- Check for other Spaces/apps, secret imports, syncs and proxied services using that same secret. Disable or update those dependents first. Disabling one Space does not disable another Space or invalidate externally held copies.
- Use the secret’s Delete action, confirm only that secret, complete any required approval workflow, and verify it is absent in that environment/path.
- Leave the Commons record disabled. Ask a gateway operator to retire unused proxy/configuration references. Commons does not poll Infisical for deletion and must not claim the secret is deleted. Restore/retention/backup behavior remains governed by Infisical’s configuration, not this action.
- If the key must stop working everywhere (especially after compromise), revoke it in the originating provider too. Deleting the vault copy is not provider revocation. Update other legitimate consumers before revoking a shared key.
Approving an agent
Each credential card has an Agent access picker for a signed-in credential owner. An owner or maintainer can assign an active Space agent through the write API, including before gateway setup. The card labels such assignments Waiting for gateway setup. Assignment alone neither creates a destination policy nor reveals a value. Once an operator binds a managed connection, credential-based access requires all credentials on that connection to be active/stored and assigned to that agent. Assigning one of a service’s keys never implicitly authorizes the others. Remove access removes that credential assignment and revokes any legacy connection-wide grant for the same agent that would retain access. Disabling a credential removes its assignments and those on its connection. Revocation also applies to outstanding tickets at redemption. Already authorized calls may finish. The connection-level form remains available for explicit whole-connection grants; those grants still authorize all of that connection’s credentials. The owner-only page also supports selecting an active agent and named connection. The write API permits owners and maintainers to grant that access. Managed connections consult the database grant on every discovery/ticket request. Production gateway redemption also rechecks current authority. Destructive methods can additionally require an exact, expiring, single-use approval by a Space owner, maintainer, or approver. For the initial deployment, use one deploy agent per Space (for examplets-deploy) and grant only that Space’s publisher connection. Do not grant
general vault access or reuse a broad Railway account token.
Agent requests and service signups
Agents use MCPrequest_credential or POST /v0/spaces/:space/credential-requests
with service_name, kind (credential or signup), reason, and optional
website_url and UUID request_id. They must be active members of the active
Space. Never put keys or passwords in a request. list_credential_requests /
GET on the same REST path returns only the caller’s own requests.
Humans review Requested credentials & signups in Space credentials. They
can add a credential with the service/website prefilled, then select a stored
credential and Assign & fulfill. This atomically assigns the requesting
agent and resolves the request; a pending setup still blocks calls. Dismiss
request resolves it without access. A signup can be marked complete after
the human creates the account; Commons never creates provider accounts itself.
Only credential owners/maintainers (or server break-glass authority) may resolve
requests. Resolved requests remain in history. Public audit events contain IDs
and statuses, never the request reason, website, or credential value.
Deployment configuration
Native execution uses the same Spaces server and database. See native execution configuration for destination bindings, the scoped reader identity, readiness, and the cutover runbook. Live authorization calls the existing Spaces authority function directly, including a second check after the vault read and before the provider request. The Commons API service needs:COMMONS_CREDENTIAL_CONNECTIONS_JSON: connection policies. SetmanagedAccess: true;allowedActorsis only an idempotent migration seed.COMMONS_CREDENTIAL_DEFINITIONS_JSON: safe credential definitions.INFISICAL_WRITER_CLIENT_IDandINFISICAL_WRITER_CLIENT_SECRET: a separate Universal Auth machine identity with create/update permission only for the approved project/environment/path.INFISICAL_PROJECT_ID,INFISICAL_ENVIRONMENT, andINFISICAL_DOMAIN.
Legacy external authorization rollout
- Deploy the Commons API/web with
POST /v0/credential-gateway/authorize. This internal endpoint accepts onlyCREDENTIAL_GATEWAY_ISSUER_KEY, not human sessions, agent keys or the steward key. It returns only an authorization boolean; the request contains identity/binding metadata, not secret values. - Configure the gateway’s
GATEWAY_AUTHORIZATION_URLtohttps://commons.diy/v0/credential-gateway/authorize(use your own Commons host on other deployments), then deploy the gateway. The gateway uses its existing matchingGATEWAY_ISSUER_KEY; no new credential is needed. HTTPS is required in production and redirects are prohibited. - Verify
/readyzand an allowed synthetic call. Production execution fails closed if the authorization URL is absent. Bound Disable requests check the issuer-authenticated/v1/authorizationcapability endpoint before claiming success. On nonstandard hosts set the API’sCREDENTIAL_GATEWAY_AUTHORIZATION_URLto the same expected URL; normally it is derived fromPUBLIC_HOST. - Issue a synthetic ticket, disable its fixture credential, and confirm redemption denies it without upstream execution. Verify other Spaces and audit trails, without disabling real service credentials for a smoke test.
initialStatus: "active" only when an administrator has independently
verified that the named value already exists in that exact Infisical path. It
is a one-time display metadata seed, never a secret-store read.
Audit and incident response
Hidden value and recent gateway usage
The credential card shows a fixed hidden-value mask for stored metadata; it does not read the Infisical value or disclose its length. Imported records are explicitly labeled as metadata, not a fresh verification of vault contents. Rotation lives under Rotate credential… rather than looking like an empty credential field. Disabled/unconfirmed entries do not claim a stored value. Each card includes Recent credential usage (three visible events, up to ten with expansion), filtered to its Space and connection. Times show relative age plus a local calendar label, such as 5 min ago · Today, 5:10 PM or 2 days ago · Sun, Sep 6, 9:50 PM. Hover for the exact local timestamp. This is connection history across rotations, not exact secret-version attribution or usage of the key outside the gateway. Multiple credentials bound to one connection share history. A provider response/HTTP 200 is not necessarily business success; one call can produce multiple audit events. Missing audit configuration, unavailable data and an empty feed are separate states. Each agent grant row also has View activity, an on-demand expansion scoped to that agent and connection, with refresh. External mode also offers a correspondingly filtered gateway link. It shows time, request method/host, named destination, task/run context and recorded outcome—not request bodies or an inferred deployment result. Theagent
query accepts a Commons agent handle; the API derives the same canonical actor
URL as ticket issuance. It validates the gateway’s echoed actor filter and each
event, and applies the filter before the ten-event limit. Old/unfiltered responses
fail closed. The history API does not require a still-active agent grant, so
authorized Space humans can inspect history after revocation; it still requires
a credential record and known agent identity. The regular credential card retains
all-agent history. Browser requests use the human session, never an audit key.
The agent access and human governance forms use the shared member autocomplete
(also used for payment access and task offers). Search by display name or
@handle, then explicitly choose a result. Typing clears any previous selection;
only the selected canonical handle is submitted, not search text or a display
name. Candidate lists remain scoped to the existing Space/type rules and all
server-side authority checks remain in place. Selecting an agent does not grant
access until the human submits Grant access.
GET /v0/spaces/:space/credential-control/credentials/:credential/activity
requires a live human sign-in session with an explicit Space credential owner
role, just like credential metadata. Maintainer, approver, and server roles or
the deployment key do not bypass this read boundary. The API resolves the connection from the credential row,
ignores client-selected connection filters, and rechecks authority on every read.
It returns only allowlisted event metadata (agent, method/host, outcome, time,
task/run/purpose), never raw URLs/paths, headers, bodies, fingerprints or secret
references. Disabled records retain access to history for authorized humans.
In native mode activity reads the Spaces database directly. No audit-reader key
or dashboard login is needed. The private page links to the
Spaces service on Railway.
Railway authentication remains separate; no credentials are included in links.
For legacy external mode only, privately configure the Commons API with
CREDENTIAL_GATEWAY_URL and CREDENTIAL_GATEWAY_AUDIT_READER_KEY from the
existing gateway reader identity. Optional CREDENTIAL_GATEWAY_PUBLIC_URL and
CREDENTIAL_GATEWAY_RAILWAY_SERVICE_URL provide external dashboard/service
links. Never use NEXT_PUBLIC_ variables or expose these keys to agent clients.
The gateway’s /v1/events now accepts connectionId, order=desc, and exclusive
before=<sequence> for older pages. Default ascending since behavior remains
compatible with audit exporters. New responses echo order/scope; Commons rejects
older/mis-scoped responses rather than showing the wrong credential’s history.
The UI shows newest events first and paginates older events. Statistics describe
the loaded page, not lifetime totals. Its topology remains a deployment snapshot.
Verification for this change: local API-to-gateway authorization/isolation,
PostgreSQL-compatible query parity using PGlite, memory replay/history tests,
redacted DTO and fail-closed tests, and browser checks using synthetic fixtures.
Production PostgreSQL performance and live server-only key wiring require a
deployment check; no provider call is needed to verify this read-only feature.
Commons events record role grants/revocations, connection grants/revocations,
credential rotations, exact approvals, approval consumption, and ticket
issuance. The Credential Gateway separately records the bounded upstream call.
To contain an incident: disable affected connections, revoke the agent’s Commons
key and the compromised upstream key at the provider, then inspect both event
streams. Replacing a vault value alone does not revoke the old upstream key.