Skip to docs content
Browse documentation
On this page

Secrets

How Minion lets your agent use your API keys, tokens, and private keys without ever reading them: no capability returns a value, {{secret:name}} placeholders resolved at the network boundary, host approval, expiry, and where each kind of credential lives. Load this when someone asks how credentials work or whether the agent can see a key.

A secret is a credential stored on your Minion organization: an API key, a personal access token, a webhook signing secret, a private key. Your agent can write code that uses a secret. It can never read one.

The rule: no capability returns a secret value

The secrets capabilities are secrets.list, secrets.set, secrets.setMany, secrets.jwtSign and secrets.delete. None of them returns a secret value. secrets.list returns metadata only: names, descriptions, approved hosts, expiry, and whether the secret may be used for webhooks or JWT signing.

This is why you can hand an agent a job that needs your GitHub token without the token ever entering the prompt, the transcript, or the model provider's logs. The same is true for every agent connected to the organization: the secret is shared; the value is shared with none of them.

How code uses a secret

Code refers to a secret by name. Minion substitutes the value at the network boundary, on the final outbound request, and only for hosts an owner or admin approved.

  • Placeholders in fetch. {{secret:githubAccessToken}} in a URL, header, or body of an outbound fetch resolves when the request leaves Minion. This is not general string interpolation; it works only in fetch. A placeholder is refused in the hostname.
  • Signed JWTs. secrets.jwtSign signs a JWT with a stored key and returns the compact token, never the key. An owner or admin must first allow JWT use for that secret on the Secrets page; host approval alone doesn't permit signing. RS*, PS*, ES* and EdDSA use a PKCS#8 PEM private key. HS* uses key material in base64 (the default), base64url or UTF-8, and rejects keys shorter than the hash size. For a service-account JSON secret, pass keyField to sign with one field of it.
  • Webhook signing secrets. A provider-issued signing secret (Stripe, Sentry, Slack) must be allowed for webhook use on the Secrets page before a package webhook can verify with it. See Inbound webhooks .

Placeholders are live tokens. Do not paste one into an issue body, a comment, a log line, or a returned string.

Host approval

Host approval decides which destinations a secret may be sent to. A secret with an empty host allowlist blocks every placeholder fetch, including from packages you wrote yourself. Owners and admins approve hosts on the Secrets page : an exact host such as api.github.com, or *.example.com for any subdomain (a wildcard doesn't cover the bare domain). Minion never approves a host automatically; an ad hoc smoke test that happened to work does not widen the allowlist.

Only owners and admins can add or change secrets and approve hosts. Members can use them from code.

OAuth tokens are different

OAuth access and refresh tokens live on the integration, refresh host-side, and do not appear in the secrets list. A pasted API key is a secret; a GitHub login is an integration. See Packages, integrations, and MCP servers .

Expiry

A secret can carry an expiry (expiresAt, an ISO timestamp or a YYYY-MM-DD date). An expired secret stays listed, but placeholders treat it as missing, so Minion stops sending the value.

Adding a secret

  • Pasting a key or PAT: the agent sends you to the Secrets page ; you paste the value into the form, never into chat.
  • A token that already exists inside trusted code (a key the package just minted): secrets.set persists it without returning it.
  • Building an integration around one or more secrets: Secret-backed integrations .

Where to go next