For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /reference/services/metallo/contexts/member_credentials/README.md.

Member Credentials

Member Credentials is the Metallo context that holds a member's offline consent for native Site work and serves one fresh access token per native action. Each Slurm job runs with the member's personal credentials; nothing is impersonated. See ADR-0035.

Aggregate

domain.consent.OfflineConsent is one login's offline grant. A member has at most one active consent, and a second login replaces it: the incoming offline token becomes the Run's token and the earlier consent moves to superseded and waits for the issuer to confirm its revocation. The other terminal states are lost (the issuer refused the stored refresh token), expired (its measured window ended) and revoked (the issuer confirmed the revocation; the row keeps no sealed value).

The record never contains the refresh token. It carries a sealed value bound to the consent identity, so a sealed value cannot open in another row. Only the owner adaptor's sealer can open it, and no token reaches a log, a command, an outcome or a reply.

Operations

OperationHandlerRules
POST /member-credentials/v1/consentsMemberCredentials.acceptLogin hand-off behind MEMBER_CREDENTIALS_INTAKE_KEY, on the Site API inside the cluster (the gateway forwards only /v1/site/ paths); recorded or unchanged
POST /v1/site/commands/{commandId}/member-tokenAttemptMemberAccess.issueRuntime's per-action token for one unacknowledged Slurm Attempt of that member
Revocation sweepMemberCredentials.revoke_pendingRetries issuer revocation for ended consents every 60 seconds
Consent refreshMemberCredentials.refresh_idleEvery MEMBER_CREDENTIALS_REFRESH_SECONDS, refreshes every active consent due inside two intervals, a page at a time, of a member who still holds Project execution authority. The Site API connects that authority only with SITE_API_EXECUTION_AUTHORITY_ENABLED=true; without it nothing is refreshed and an unused consent ends after the seven-day idle timeout

The token route lives under the command scope it serves, /v1/site/commands/: the path names the command, the body names its Attempt only, and the Site and environment are the ones the bearer proves. A Site API can therefore scope the whole command prefix without a third route family. It is the Runtime's own commands grant that covers the route (DD-0059 §8), so no third native scope exists; a psb_ bearer is accepted only with that scope and the slurm environment, while a Kubernetes Runtime keeps its site-control audience. The grant's Site must be the one this listener serves, the single setting SITE_API_SITE_ID every native route reads (no fallback, and SSH_ACCESS_SITE, when present, must name the same Site), and the command's saved attemptId must match the request.

Every other case gets one refusal: another Site, another environment, an unknown command, a command of another Attempt and an acknowledged command all answer 403 member_token_refused with the same body, so a caller cannot learn whether an Attempt exists. A bearer outside the commands grant stops earlier with a plain 403 forbidden, which says nothing about any Attempt. A consent that is missing, lost, expired, superseded or revoked becomes ConsentRefused with one fixed code. The Runtime records a terminal Attempt refusal for member_consent_missing, member_consent_lost, member_consent_expired and member_consent_revoked, after releasing repository access and cleaning its workspace. Execution Core prevents automatic retries and includes a sign-in-again notice in the Run's typed projection. Temporary owner and transport failures remain retryable.

Rotation happens under a per-member advisory lock and the row's FOR UPDATE. The adaptor persists the new sealed value and generation before the caller uses the access token, so a crash between the issuer's rotation and the commit leaves a consent that is provably unusable rather than one that silently continues with a stale token.

The refresh worker is what keeps an idle Run inside the issuer's idle window: without it, a Run that performs no native action for longer than the idle timeout loses its consent even though the 30-day maximum has not been reached (ADR-0035). It takes the same per-member lock as a native action, so a refresh and an action never rotate the same token twice; it keeps no access token; and it lists only an active consent whose issuer-reported deadline is still ahead. Project execution authority comes from the resource view's member_generations, which keeps a Party that left a Project as inactive, so a member who left is never refreshed; when that evidence is unavailable nothing is refreshed for that member and the next pass asks again. The worker runs in the Site API, beside the routes. While the Run path is paused it has no such authority, and with no Run to keep alive it only retries revocations.

Configuration

VariablePurpose
MEMBER_CREDENTIALS_INTAKE_KEYShared key with the login service; at least 32 characters
MEMBER_CREDENTIALS_ISSUERExpected issuer of every consent
MEMBER_CREDENTIALS_CLIENT_IDThe login client the offline consent belongs to
MEMBER_CREDENTIALS_CLIENT_SECRETRefreshes and revokes at the issuer's token endpoint
MEMBER_CREDENTIALS_CA_FILETrust for the issuer
MEMBER_CREDENTIALS_SEAL_KEYSeals the stored refresh token; 32 bytes as 64 hex characters
MEMBER_CREDENTIALS_REFRESH_SECONDSSweep refresh interval; three days by default, and it must leave one interval of margin inside the seven-day idle timeout
SITE_API_SITE_IDThe Site API's one Site; every Runtime grant must name it. There is no fallback, and SSH_ACCESS_SITE, when present, must name the same Site

All six MEMBER_CREDENTIALS_* values are required together, and the listener refuses to start if it cannot name its Site; without an intake key it serves only its other routes.

Storage

member_credentials owns its PostgreSQL database and schema: one active row per member (enforced by a partial unique index), the ended rows kept until the issuer confirms revocation. It has no broker, no platform database and no Runtime access.

Page source

Source snapshot · Revision f928834c8.