# Keep each customer's credentials in its own environment

> How to give each of your customers an environment of their own, so their sandboxes receive their credentials and nobody else's, and how to delete it all when they leave.

This guide shows how to give each of your customers sandboxes that receive that customer's credentials, such as their GitHub token or Anthropic API key, and no other customer's.

Each customer gets an environment. An environment holds one value for each secret name, so `GITHUB_TOKEN` can hold a different value for every customer, and your code names the same secret for all of them.

## Before you start

- [`div login`](https://docs.divergentlabs.xyz/compute/cli/login.md) has saved a key with the `secrets:write` and `sandboxes:write` scopes. Keys created by `div login` have both.
- The examples use `acme` as the customer. Use your own id for each customer.

## 1. Create an environment for the customer

```bash
div secrets env add acme
```

Environment names are lower case letters, digits and dashes, up to 63 characters, starting with a letter or digit.

## 2. Set the customer's secrets

```bash
printf %s "$ACME_GITHUB_TOKEN" | div secrets set GITHUB_TOKEN --environment acme --products sandboxes
printf %s "$ACME_ANTHROPIC_KEY" | div secrets set ANTHROPIC_API_KEY --environment acme --products sandboxes
```

- Use the same names in every customer's environment.
- `--products sandboxes` keeps the secret out of runs. Runs read only the `default` environment, so no run receives it.
- `div secrets --environment acme` lists the customer's secrets. Values are never shown.

## 3. Create the customer's sandboxes

```bash
SB=$(div sandbox create --environment acme --secret GITHUB_TOKEN --secret ANTHROPIC_API_KEY --metadata customer=acme)
```

- The sandbox receives the values from `acme`, and only the secrets it names.
- `--metadata customer=acme` labels the sandbox. `div sandbox ls --metadata customer=acme` lists the customer's sandboxes.
- `div sandbox resume` reads the secrets from `acme` again. A fork keeps `acme`.
- The values are masked in the output of `div sandbox exec` and in the messages of [coding agents](https://docs.divergentlabs.xyz/sandboxes/agents.md).

At the [`ssh div.io` prompt](https://docs.divergentlabs.xyz/sandboxes/cli/ssh-prompt.md), the same command is `new --environment acme --secret GITHUB_TOKEN`.

## 4. Show the customer's sandbox on screen

A sandbox that names any secret cannot have a [sandbox token](https://docs.divergentlabs.xyz/sandboxes/cli/sandbox.md#token), in any environment. Minting one fails with `sandbox_has_secrets`. Choose one of these instead:

- **For people in your org:** open the sandbox in the dashboard, signed in with your own account, or save the screen with `div sandbox screenshot`. Neither needs a sandbox token.
- **For a screen embedded in your product:** create a separate sandbox without secrets for the work your customer watches, and mint its token as in [Add computer use to your product](https://docs.divergentlabs.xyz/sandboxes/computer-use.md).

## 5. Delete the environment when the customer leaves

1. Delete the customer's sandboxes.

   ```bash
   div sandbox ls --metadata customer=acme | cut -d' ' -f1 | xargs -n1 div sandbox rm
   ```

2. Delete the environment. This also deletes every secret in it.

   ```bash
   div secrets env rm acme
   ```

`div secrets env rm` fails with `environment_in_use` while any sandbox in the environment is not deleted, stopped sandboxes included. The message names them. Delete them with `div sandbox rm` and run it again.

## Related

- [`div secrets`](https://docs.divergentlabs.xyz/compute/cli/secrets.md)
- [`div sandbox create`](https://docs.divergentlabs.xyz/sandboxes/cli/sandbox.md#create)
- [Secrets in a sandbox](https://docs.divergentlabs.xyz/sandboxes.md#secrets)
