# Secrets

> Give functions API keys and passwords without putting them in code or showing them to the people who run them.

Source: https://callables.app/docs/secrets

Secrets give functions API keys, passwords and tokens without putting them in code or showing them to the people who run them.

## Declare what a function needs

List the environment variables in `secrets`, and read them inside the function:

```python
import os

import stripe

from callables import deploy


@deploy(title="Refund a charge", secrets=["STRIPE_KEY"])
def refund(charge_id: str) -> str:
    stripe.api_key = os.environ["STRIPE_KEY"]
    stripe.Refund.create(charge=charge_id)
    return f"Refunded {charge_id}."
```

The code only names the secret. The value never appears in the repo.

## Set the value

After you push, set the value in the web app. Values are stored encrypted and injected as environment variables each time the function runs. A function only receives the secrets it declares.

Each secret can be set at one of three levels:

| Level | Applies to |
|---|---|
| Team | Every function on the team |
| Project | Every function in one project |
| Function | One function |

When the same name is set at more than one level, the most specific wins: function, then project, then team. Builders set and change secrets. People who only run a function never see the values.

## Missing secrets

A declared secret that nobody has set doesn't block the run. The variable is simply missing, and builders see a "missing secrets" warning on the project. For an optional secret, read it with `os.environ.get("NAME")` and handle it being missing.

## Groups

A [group](https://callables.app/docs/groups) can declare secrets once for every action in it:

```python
from callables import Group

billing = Group("billing", title="Billing", secrets=["STRIPE_KEY"])
```

## Key files

Each secret is a single value. For a `.pem` file or a service account JSON, paste the file's contents as the secret, and have your code read it from the variable.

## Locally

`call local` and `call <function>` read the same variables from your environment, so a `.env` file works well. Keep it in `.gitignore`.

## Rules

- Never hard-code a key, even for testing.
- Never take a key as a form input.
- Read secrets inside the function, never at module level: modules are imported at build time, when secrets aren't set.
- Give each function the narrowest key that works, such as a restricted Stripe key.
