Secret-backed integrations
Default non-OAuth recipe for secret-backed integrations: research auth, collect secrets on the Secrets page, approve hosts, run a smoke test, then build the downstream package.
Use this guide after the integration bootstrap when the integration uses one or more saved secrets instead of an OAuth integration.
This is the default path for many automation-oriented integrations:
- API keys
- personal access tokens
- account IDs plus tokens
- static credentials that the user can copy from a provider dashboard
Goal
Keep the integration flow simple:
- research the provider's auth requirements (see step 1 below)
- collect the required secret values through the Secrets page
- run one real authenticated smoke test
- only then build the downstream package or workflow
Do not jump straight to a package app or saved package if the secret and smoke-test path is unclear.
Default recipe
- Identify the provider's auth contract.
- When the contract is unfamiliar, read the provider's official docs and verify every URL against the provider's own domain.
- Confirm which fields are secrets and which are readable config.
- Prefer the provider's native credential shape when possible.
- If the API also needs readable configuration such as an account ID, base URL, region, workspace slug, or default sender, store those in memories or
packageStorage(), not as secrets.
- Check whether the needed secrets already exist.
- Call
minion.secrets.list()insideexecute. It returns names, approved hosts and expiry, never values.
- Call
- If any secret is missing, stop and send the user to the Secrets page .
- Ask for each missing secret by name.
- Include the provider dashboard URL and short creation steps when helpful.
- Do not ask the user to paste the secret into chat.
- Wait for the user to confirm the secret is saved.
- Run one cheap authenticated smoke test in
execute.- Use the same secret names and request shape the final package will use.
- Prefer a small read-only endpoint such as account info, profile info, or a single-item list endpoint.
- If the smoke test is blocked on host approval, stop.
- Tell the owner or admin which host to approve on the Secrets page.
- Wait for them to approve it.
- Retry only after approval.
- After the smoke test passes, build the dependent package or workflow.
- Prefer plain package exports for simple automations.
- Use a package app only when the user actually needs interactive UI, browser-side forms, or a hosted page.
- After the package is saved and published, verify it from
executewith a staticminion:@your-org/package/exportimport before treating it as complete. Prefer a read-only export, or a dry-run input that actually reads the secret (for example an authenticated read-only API call), so verification proves access without external side effects.
Secret names and readable config
Use descriptive names that reflect the real auth contract:
- good secret names:
providerApiKey,providerAccessToken,providerAccountToken - good places for readable identifiers and defaults (account id, region, sender): memories for durable facts the agent should recall, and
packageStorage()for package runtime knobs
If the auth contract has multiple fields, save only the truly sensitive fields as secrets. Keep readable identifiers and defaults out of the secret store.
Using a saved secret in fetch
Saved secrets are referenced by placeholder, never by plaintext. Inside execute (and package code), put {{secret:name}} in the URL, headers, or body of an outbound fetch. Minion resolves the placeholder for approved hosts only:
const response = await fetch('https://api.example.com/v1/me', {
headers: {
Authorization: 'Bearer {{secret:providerAccessToken}}',
},
}) Rules:
minion.secrets.list()returns metadata only (names, approved hosts, expiry). Use it to find the right secret name, then reference that name in a placeholder.- Placeholders only resolve in outbound
fetch; they are not general string interpolation. - Never echo a resolvable literal placeholder into chat, logs, issue bodies, or any content that may later be sent over
fetch. To mention the syntax in prose, use the inert{{secret:<name>}}form: angle brackets are outside the name charset, so it never resolves. - Secrets are shared across the organization. Any package or execute call can refer to one, but only toward its approved hosts.
When the Secrets page is enough
In the common case, the Secrets page is the whole setup surface.
Use it when:
- the provider gives the user one or more static secret values
- the final request can use those secrets directly in
fetch(...) - the only extra work after saving the secret is host approval and a smoke test
This should be the default assumption for non-OAuth integrations.
When to avoid package apps
A package app is not the default integration path.
Do not build one just to:
- collect a normal API key or token
- collect an account ID or other readable config
- work around the need to ask the user for a secret through the Secrets page
A package app is the exception when the setup requires something the Secrets page cannot express cleanly, such as a provider-specific setup wizard with multiple non-secret choices, or a required transformation step that cannot be represented by saving the raw secret plus readable config directly.
Even then, keep the UI focused on setup. The downstream package should wait for the post-setup smoke test.
Recommended chat phrasing
For a new secret-backed integration, the default response shape is:
- state the auth requirement you found
- ask the user to save the required secret or secrets on the Secrets page
- say you will run a smoke test after they confirm setup
- say you will build the package only after the smoke test passes
Example:
- "This API uses an account ID plus a token. Please save
providerTokenon the Secrets page and approveapi.example.com. I will keepproviderAccountIdas readable config (memory or package storage), run a real authenticated smoke test, and then build the package."
Anti-patterns
Avoid these mistakes:
- building a package app before checking whether the Secrets page is enough
- saving readable config as a secret
- saving the downstream package before the smoke test passes
- assuming a saved secret automatically approves outbound hosts
- inventing a provider-specific flow when one or two secrets plus a smoke test would do