Skip to content

Secrets

Secrets let you store sensitive values - API keys, tokens, connection strings - outside your tool’s code. Instead of hardcoding a secret in your handler, you store it once at the workspace level as a Secret and Rival injects it at runtime. Your code reads it by name, and the value is never embedded in the tool source or visible to anyone running the tool from the marketplace.


Where secrets live

Secrets are managed at /user/secrets - open the settings sidebar and select Secrets. Each secret is a name/value pair scoped to your workspace.

If you embed credentials directly in tool code, they become part of the published version snapshot and are visible to anyone with code-level access. Storing them as Secrets keeps them in a separate, access-controlled store and makes rotation easy - update the value once and every tool that reads it picks up the new value on the next run.


Creating a secret

  1. Open Settings → Secrets (or go to /user/secrets).
  2. Click New secret.
  3. Give it a descriptive name in uppercase with underscores, for example OPENAI_API_KEY or DATABASE_URL.
  4. Paste the value and save.

Values are encrypted at rest and not displayed again after saving. The naming convention is just a convention - it isn’t enforced - but it keeps things consistent across your team.


Attaching secrets to a tool

Creating a secret at the workspace level does not automatically make it available to every tool. You attach the secrets a specific tool needs from Studio’s Secrets tab. This is intentional: a tool that processes user-facing text has no reason to read your payment-processor credentials.

Open the tool in Studio, go to Secrets, and select the secrets this tool should be able to read. Once attached, the secret is injected into the tool’s runtime environment on every run. The same rows are also available as a strip under the file tree on the Code tab, if you’d rather not leave the editor.

Attachments are per version. The Secrets tab shows what the version you’re looking at reads, so an older published version keeps the secrets it was published with even after you attach or remove one on the version you’re working on.


Asking the runner for a key instead

Everything above ships your credential: every run of the tool, including runs by marketplace users, spends your key. If the tool wraps a paid third-party API, that’s usually not what you want.

A secret can instead be declared an external key - the version publishes the key’s name and a description, and whoever runs the tool picks which of their own secrets fills it. Turn on the External toggle on the secret’s row in the Secrets tab to declare one. See External Keys for the whole flow, including how the mapping travels in the X-Env-Keys header on API calls.


Reading secrets in your tool code

How you access secrets depends on the language your tool uses.

Python

import os
def cortexone_handler(event, context):
api_key = os.environ.get("MY_API_KEY")
if not api_key:
return {"statusCode": 400, "body": {"error": "API key not configured"}}
# use api_key ...
return {"statusCode": 200, "body": {"ok": True}}

Use os.environ.get("KEY_NAME") rather than os.environ["KEY_NAME"] so missing variables return None instead of raising a KeyError.

Python 3.13 — Fast

import json
def cortexone_handler(event, context):
api_key = process["env"].get("MY_API_KEY")
if not api_key:
return {"statusCode": 400, "body": {"error": "API key not configured"}}
# use api_key ...
return {"statusCode": 200, "body": {"ok": True}}

process["env"] is always available without any import. os.environ does not work in this runtime.

JavaScript

function cortexone_handler(event, context) {
const apiKey = process.env.MY_API_KEY;
if (!apiKey) {
return { statusCode: 400, body: { error: "API key not configured" } };
}
// use apiKey ...
return { statusCode: 200, body: { ok: true } };
}

Lua

function cortexone_handler(event, context)
local api_key = process.env.MY_API_KEY
if not api_key then
return {statusCode = 400, body = {error = "API key not configured"}}
end
-- use api_key ...
return {statusCode = 200, body = {ok = true}}
end

Security

Secret values are encrypted at rest and never returned in API responses or shown in the dashboard after the initial save. Marketplace users who run your tool cannot see the secrets or their values - they only interact with the inputs and outputs you define.

Secrets are scoped to your workspace. Members of your organization can see secret names (so they can attach them to tools), but values are not exposed to non-owner roles.