Gateman
Documentation/Access stored credentials

Access stored credentials

capability_id: secrets:read
display_name: Access stored credentials
ui_capability_key: access_credentials
scope: secrets:read
endpoint:
  method: POST
  path: /secrets/get
operation: secrets.get
billable: true
environment: required

Purpose and authorization

This capability lets an active, authenticated Gateman application retrieve eligible credential values stored for that application.

It covers two credential categories:

  • Custom credentials: customer-defined logical names with independently optional production and test values.
  • Provider credentials: provider-specific stored names, including eligible managed SES and S3 runtime credentials, subject to provider retrieval authorization.

The application MUST have the secrets:read scope and authenticate with Contract v1. Provider credentials also require the relevant provider's application-scoped Allow app retrieval setting. The setting applies to eligible names for that provider; it is not a per-field or per-environment permission.

Provider relay scopes authorize Gateman to use a credential internally. They do not authorize the application to receive that credential. This capability is also separate from database-password retrieval, public configuration, provider provisioning, and setup credentials.

Implementation contract

Request

POST /secrets/get
Content-Type: application/json
X-GM-App: app_...
X-GM-Ts: 1710000000
X-GM-Sig: <Contract-v1-signature>
X-GM-Credential-Request-ID: 0123456789abcdef0123456789abcdef

The request MUST use the authenticated and signed Contract v1 transport. The credential-request identifier is a separate required signed component for this route.

{
  "environment": "production",
  "keys": [
    "MY_API_KEY",
    "STRIPE_SECRET_KEY"
  ]
}

Request fields:

FieldRequiredContract
environmentYesString: production, staging, or development.
keysYesArray of requested names; at most 10 submitted entries.

Names are retrieved by exact name. There is no wildcard or list-all operation. The route applies its normal input normalization, skips non-string, empty, and overlong names, and does not return per-name diagnostics.

Custom credential selection

Custom credentials use one logical name with two independently optional values:

Request environmentSelected custom value
productionProduction value
stagingTest value
developmentTest value

There is no fallback between slots. If the selected value is not configured, the name is omitted. The caller requests the same logical name in all three environments.

Provider credential selection

Provider credentials are retrieved by their configured names, independently of the request environment. For example, STRIPE_SECRET_KEY retrieves the production-named credential, while STRIPE_SECRET_KEY_TEST retrieves the test-named credential. Gateman does not automatically substitute one for the other.

Examples, when configured and authorized:

ProviderProduction-named credentialTest-named credential
StripeSTRIPE_SECRET_KEYSTRIPE_SECRET_KEY_TEST
Stripe webhookSTRIPE_WEBHOOK_SECRETSTRIPE_WEBHOOK_SECRET_TEST
SquareSQUARE_ACCESS_TOKENSQUARE_ACCESS_TOKEN_TEST
PayPalPAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRETPAYPAL_CLIENT_ID_TEST, PAYPAL_CLIENT_SECRET_TEST

Other providers commonly use shared names across environments, including email, SMS, storage, anti-bot, and general relay credentials. Do not infer that every provider has production/test pairs.

Provider operations may independently map their own environment field to provider credentials. That operation-level mapping does not change this route's exact-name disclosure contract.

Successful response

HTTP/1.1 200 OK
Cache-Control: no-store
Content-Type: application/json; charset=utf-8
{
  "ok": true,
  "secrets": {
    "MY_API_KEY": "example-custom-value",
    "STRIPE_SECRET_KEY": "sk_example_not_real"
  }
}

The secrets object contains only requested, configured, and authorized names. Unknown, unavailable, invalid, and retrieval-disabled names are omitted. An empty object is valid. Multiple requested names do not produce multiple operations.

Managed values and exclusions

Eligible managed SES and S3 runtime credentials use ordinary provider credential names and may be returned when the secrets:read scope and the corresponding provider retrieval setting authorize disclosure.

Temporary setup credentials, internal control credentials, derived provider access-token caches, and provider configuration metadata are outside generic retrieval. Database passwords use db:read and POST /db/get, one named password at a time.

Stripe webhook secret

Stripe webhook secrets have a separate route:

POST /stripe/webhook-secret

That route requires stripe:webhook:read. An eligible Stripe webhook secret may also be returned by /secrets/get when secrets:read and Stripe Allow app retrieval authorize it. These are separate authorization paths.

Errors

Responses use the shared JSON error envelope. Relevant route outcomes are:

ConditionStatus and error
Missing, invalid, stale, or unsigned authentication; invalid credential request IDHTTP 401; the route's authentication error, such as Invalid credential request ID or Invalid signature.
Missing secrets:readHTTP 401, Scope not allowed, under the current authentication contract.
Invalid JSONHTTP 400, Invalid JSON.
Missing environmentHTTP 400, Application environment is required.
Unsupported environmentHTTP 400, Unsupported application environment.
keys is not an arrayHTTP 400, Invalid request.
More than 10 submitted entriesHTTP 400, Too many keys requested.
Replayed credential-request identifierHTTP 409, Credential request already used.
Monthly operation allowance exhaustedHTTP 403, monthly_operation_limit_reached, with allowance details.
Application concurrency limitHTTP 429, app_concurrency_limit_exceeded, with Retry-After.
Application concurrency guard unavailableHTTP 503, app_concurrency_guard_unavailable.
Credential claim infrastructure unavailableHTTP 503, Credential retrieval unavailable.
Secret storage or decryption unavailableHTTP 500, Secret store unavailable.

The authentication layer returns HTTP 401 for an unauthorized scope in the current implementation; integrations MUST follow the actual response rather than assuming all authorization failures are HTTP 403.

Operation and replay obligations

One accepted request consumes one secrets.get operation, regardless of the number of requested names. A request that returns no eligible values can still consume an operation. Authentication, scope, malformed-request, and replay rejections occur before operation reservation.

X-GM-Credential-Request-ID MUST:

  • contain exactly 32 lowercase hexadecimal characters;
  • be included in the Contract v1 signature;
  • be fresh and single-use for the application.

Gateman claims the identifier before credential lookup. A later lookup or decryption failure may still consume it. Claims are retained for 11 minutes; a retry requires a new identifier.

Official PHP, Node.js, Python, and Go clients generate this identifier for /secrets/get when using their general request methods. No client is privileged, and clients do not automatically retry.

Retry semantics

  • Definitive rejection before disclosure, such as invalid authentication or request validation, did not disclose a credential. The response must still be handled according to its status and error; not every rejection is safely retryable.
  • A transport failure or ambiguous outcome may occur after Gateman has processed the request. The caller MUST NOT assume disclosure did not occur.
  • A claimed credential-request identifier cannot be replayed during its active protection window. A new attempt requires a fresh identifier.

A deliberately implemented retry policy MAY account for these known failure semantics. A new accepted attempt can consume another secrets.get operation. See Operation Accounting, Rate limits and concurrency, and Idempotency.

Implementation outcome

A correct integration should produce these observable outcomes:

  • Requested, authorized, and available credential values are retrieved correctly.
  • Custom credentials resolve to the appropriate environment slot without production/test fallback.
  • Provider credentials are retrieved by their exact configured names.
  • Omitted values are handled explicitly without assuming that they exist.
  • Contract v1 authentication, single-use credential-request protection, and error handling are preserved.
  • Retrieved plaintext is not inadvertently persisted or logged.

Implementation instructions for agents

  • SHOULD use an official Gateman client where appropriate. A direct HTTP implementation MUST conform to Contract v1.
  • The integration MUST supply the application's environment using only production, staging, or development.
  • It MUST request custom credentials by their logical names.
  • It MUST request provider credentials by their exact configured names and MUST NOT transform provider names based on the request environment.
  • It MUST handle omitted names explicitly; a requested name is not guaranteed to appear in secrets.
  • It MUST preserve the fresh, single-use X-GM-Credential-Request-ID mechanism and include it in the signed request.
  • It SHOULD NOT automatically retry an uncertain disclosure. A deliberate retry policy MAY use a fresh identifier and account for another accepted operation.
  • It MUST NOT enable provider retrieval or expand application scopes without the customer's explicit authorization.
  • Direct credential retrieval and provider relay operations are independent developer/customer choices; neither is implicitly required or preferred.
  • It SHOULD keep retrieved plaintext credentials in memory only as long as needed and prevent them from entering source files, .env files, logs, or other persistent locations unless the developer intentionally selects a different credential-management approach.
  • It MUST NOT represent Gateman as controlling a disclosed credential or treat disabling retrieval as revocation of credentials already disclosed or of provider-side permissions.

Reusable AGENTS.md block

<!-- gateman:begin capability=secrets:read -->
- Use the `secrets:read` Access stored credentials capability through
  authenticated Contract v1 `POST /secrets/get` with a fresh, signed,
  single-use `X-GM-Credential-Request-ID`.
- Custom credentials use logical names: `production` selects the production
  value; `staging` and `development` select the test value, with no fallback.
- Provider credentials use exact configured names; do not remap them from the
  request environment.
- Provider disclosure also requires that provider's **Allow app retrieval**
  setting; do not enable it or expand scopes without customer authorization.
- Treat omitted names as unavailable and do not automatically try alternatives.
- Keep returned plaintext out of source, `.env` files, logs, and unintended
  persistent locations.
- Disabling Gateman retrieval does not revoke credentials already disclosed or
  provider-side permissions.
- Full reference: https://docs.getgateman.com/capabilities/secrets.read/
<!-- gateman:end capability=secrets:read -->