Secret resolvers
Resolve secrets lazily at call time with env() and secretsFile() instead of hard-coding them.
Every auth strategy takes a secret as a reference, not a value, and resolves it
at call time — reach for env() and secretsFile() so the declaration carries a
capability, not a credential you have to commit.
Example
import { , , , } from 'stitchapi';
// env() reads process.env.API_TOKEN when the stitch is called, not now.
const = ({
: 'https://api.example.com',
: '/me',
: (('API_TOKEN')),
});
// secretsFile() resolves from ~/.stitch/secrets.json, falling back to the env var.
const = ({
: 'https://api.example.com',
: '/billing',
: (('BILLING_TOKEN')),
});The token is never read at declaration time, so the secret never enters the stitch's source — only the name of where to find it does.
Options
A secret is a string | (() => string). Every strategy — bearer, apiKey,
basic, oauth2 — accepts one and resolves it the moment a request goes out,
so the same declaration works across processes and machines without baking a
value in.
env(name) returns a thunk that reads process.env[name] at call time and
throws missing env var <name> if it is unset — failing loudly at the call
rather than silently sending an empty token.
secretsFile(name) reads ~/.stitch/secrets.json if present and the key is
there, otherwise falls back to the environment variable of the same name, and
throws if neither has it.
~/.stitch/secrets.json is unencrypted plaintext JSON. Restrict its
permissions (chmod 600 ~/.stitch/secrets.json), add it to your
.gitignore, and never commit it. For production workloads prefer a proper
secrets manager or env() backed by your deployment platform's secret
injection.
Why call-time resolution matters: the value is fetched only when a call is
made, so you never commit a secret and the stitch holds a capability rather than
the credential itself — the capability boundary
the product is built on. You can pass a plain string (discouraged — that hard-codes
the value), or any () => string thunk of your own, so plugging in a vault or
secrets manager is just supplying a different resolver.
Anti-pattern: don't pass a secret as a plain string — it is read at
declaration time and lives in your source and history, collapsing the
capability back into a committed credential; pass env() or secretsFile()
instead so the value resolves at call time and the stitch carries a
capability, not a credential. See Capability, not
credential.