> ## Documentation Index
> Fetch the complete documentation index at: https://docs.joystream.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Credentials and vaults

> Where JoyStream stores service credentials, how org admins audit them, how credential scope controls availability, and how tokens reach an MCP server.

A vault holds the credentials your agents use to reach outside services: a GitHub token, a Discord bot token, an LLM API key. Vaults exist at three levels, and a credential is resolved from the most specific level outward.

| Vault     | Holds                                      | Visible to                                     |
| --------- | ------------------------------------------ | ---------------------------------------------- |
| Personal  | Credentials you connect for yourself       | You only. Never visible to org admins.         |
| Workspace | Credentials the workspace's members share  | Members of that workspace                      |
| Org       | Credentials shared across the organization | Org members, subject to the credential's scope |

When an agent needs a credential for a provider, JoyStream walks these tiers and uses the first match. `jstm connection resolve <provider> --workspace <id>` prints that walk tier by tier, so you can see exactly which credential an agent will get and why.

## Org credential audit

An org owner or admin can see every service credential connected anywhere in their organization, across all workspaces — including workspaces they are not personally a member of. This is a read-and-inspect surface: you see that a credential exists and its metadata, never the secret value.

An organization is made of workspaces — the org itself, plus its teams — and each workspace can hold its own credentials. Without the audit there is no single place to answer "what is connected across my whole org, and where?"

The audit groups credentials by availability scope:

* **Org-wide** — credentials in the org vault that every workspace can use.
* **Selected workspaces** — credentials restricted to specific workspaces. A credential restricted to two workspaces appears under each of those workspace groups.

For each credential you see metadata only: provider such as `github` or `discord`, type (`SERVICE` or `LLM`), status (`ACTIVE`, `NEEDS_REAUTH`, or `REVOKED`), its scope, the owning workspace, and who connected it.

<Info>
  Values are never exposed. No surface in this feature returns token material — not the API, not the CLI, not the UI.

  Personal vaults are excluded. Credentials a user stored in their personal vault are never visible to org admins.

  Only an org owner or admin can audit. A non-admin org member sees only credentials for workspaces they belong to.
</Info>

Use the organization's Vault Settings view in the web UI, or `jstm vault audit` from the CLI.

## Credential scope

Every credential in the org vault has a scope that decides which workspaces in the org can use it:

* **Org-wide** (`all_workspaces`) — available to every workspace in the org.
* **Selected workspaces** (`selected_workspaces`) — available only to the workspaces you pick.

The labels Org-wide and Selected workspaces are what you see in the web UI and in CLI human output. The underlying values `all_workspaces` and `selected_workspaces` appear in `--json` and API payloads.

```bash theme={null}
# Make a credential available org-wide
jstm vault scope 4d90c7e2-6b18-4a55-9f31-c8ab27e05d10 --scope all

# Restrict it to specific workspaces (repeat --workspace)
jstm vault scope 4d90c7e2-6b18-4a55-9f31-c8ab27e05d10 --scope selected \
  --workspace acme-corp/finance --workspace acme-corp/revops
```

Selected requires at least one workspace. Choosing Selected workspaces without naming any is rejected up front — the UI keeps the picker open, and the CLI fails with a clear message instead of saving an empty selection.

Scope supersedes the previous per-workspace sharing model. The older `vault grant` and `vault revoke` commands have been removed. To read a credential's current scope and its selected workspaces, use `jstm vault grants`.

Only an org owner or admin can set a credential's scope, and only credentials in the org vault are scopeable. Attempting to scope a workspace or personal vault credential is rejected.

## How a token reaches an MCP server

When an agent runs a skill backed by a stdio MCP server — sending a Discord message, creating a GitHub issue — JoyStream launches that server as a subprocess and must hand it your credential. The server reads the credential from an environment variable whose name the server itself dictates: `DISCORD_TOKEN`, `GITHUB_PERSONAL_ACCESS_TOKEN`, and so on.

JoyStream resolves that name from two sources, in order.

```mermaid theme={null}
flowchart TD
    A["server.json manifest"] --> B{"Declares a secret env var?"}
    B -- yes --> C["Inject the token into that variable"]
    B -- no --> D{"Curated provider overlay exists?"}
    D -- yes --> E["Inject into the overlay's variable"]
    D -- no --> F["Fail with an error naming the service"]
```

First, the server's manifest. A well-formed MCP server declares its environment variables and marks which one is the secret. Second, a curated provider overlay: many real servers declare nothing, so JoyStream keeps a small map of provider to environment variable name, such as `discord → DISCORD_TOKEN`.

If a connector requires a credential but matches neither source, JoyStream fails with an error naming the service. It never guesses.

Each server stores its declared variables in this shape, rendered on the server's detail page:

```json theme={null}
{
  "GITHUB_TOKEN":   { "type": "secret", "required": true,  "description": "GitHub PAT" },
  "GITHUB_API_URL": { "type": "string", "required": false, "description": "API base URL" }
}
```

`type: "secret"` marks the variable that receives the credential. A secret variable carries no value or default — the value is supplied at run time from your vault, never stored in the catalog. `env_vars: null` means the manifest declared no variables; it does not mean "no authentication", only that JoyStream falls through to the provider overlay.

Whether a connector needs a credential is decided by the skill's required services, never by whether `env_vars` is populated. Only an empty required-services set means a skill is genuinely no-auth.

Some providers don't run as a subprocess at all. They're called in-process over HTTP with a bearer token — Google Workspace is the current example. These never go through environment variable injection and intentionally have no overlay entry.

If a server declares more than one secret variable, JoyStream refuses to guess which one gets the token and fails with a clear error.

## See also

* [Audit and scope org credentials](/guides/audit-and-scope-org-credentials) — walkthrough.
* [Connect a service](/guides/connect-a-service)
* [`jstm vault`](/cli/vault) and [`jstm connection`](/cli/connection)
