For third-party API keys, signing secrets and webhook tokens use ctx.secrets instead of ctx.kv. Secrets are encrypted at rest (AES-GCM with the platform master key) and stay out of your repo. The platform never writes secret values into your stdout, logs or KV, but nothing redacts a value your own code prints or logs, so treat ctx.secrets.get results as sensitive. Where you can, prefer secret-backed auth so your code never touches the value at all. Capability: storage:secrets.
Two scopes: an optional per-server override set at runtime (checked first), then the dev-level default you set once in the Dev Portal for every server that installs your plugin.
# Read: per-server override first, then your dev-portal default, else None
api_key = ctx.secrets.get("OPENAI_API_KEY")
if not api_key:
ctx.log("No API key configured for this server", level="warning")
return
ctx.secrets.set("OPENAI_API_KEY", submitted_key) # per-server override
ctx.secrets.delete("OPENAI_API_KEY") # remove the override only
Key format: 1–64 chars, letters/digits/_/-/. only. Values: 1–4096 UTF-8 chars.
Secrets also power secret-backed auth: name a stored secret in an ctx.http or ctx.ws call and the platform sends it as the Authorization header without your code ever reading it.