> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/openshell/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/openshell/_mcp/server.

# Providers

> Create and manage credential providers that inject API keys and tokens into OpenShell sandboxes.

AI agents typically need credentials to access external services: an API key for the AI model provider, a token for GitHub or GitLab, and so on. OpenShell manages these credentials as first-class entities called *providers*.

Create and manage providers that supply credentials to sandboxes.

> **Info**
>
> Providers v2 is available for profile-backed provider policy, provider-owned network rules, and gateway-managed credential refresh. This page remains the credential-focused provider command reference. For the new workflow, see [Providers v2](/sandboxes/providers-v2).

Provider profiles include metadata for known endpoints and binaries. View
the available profiles before creating a provider:

```shell
openshell provider list-profiles
```

## Create a Provider

Providers can be created from local environment variables or with explicit credential values.

For refresh-backed providers such as `google-vertex-ai --from-gcloud-adc`, `openshell provider create` now waits for the gateway to configure refresh metadata and mint the initial access token before it reports success.

### From Local Credentials

The fastest way to create a provider is to let the CLI discover credentials from
your shell environment:

```shell
openshell provider create --name my-claude --type claude --from-existing
```

This reads `ANTHROPIC_API_KEY` or `CLAUDE_API_KEY` from your current environment
and stores them in the provider.

### With Explicit Credentials

Supply a credential value directly:

```shell
openshell provider create --name my-nvidia --type nvidia --credential NVIDIA_API_KEY=nvapi-example
```

### Bare Key Form

Pass a key name without a value to read the value from the environment variable
of that name:

```shell
openshell provider create --name my-nvidia --type nvidia --credential NVIDIA_API_KEY
```

This looks up the current value of `$NVIDIA_API_KEY` in your shell and stores it.

### From the Current OIDC Login

Profile-backed token-exchange providers can store the current gateway OIDC
access token as their subject credential. The subject credential stays
gateway-only and is not emitted into sandbox environment material or static
credential bindings:

```shell
openshell provider create \
  --name custom-api \
  --type custom-api \
  --from-oidc-token
```

OpenShell infers the destination credential from the provider profile when the
profile has exactly one `token_grant.subject_token.credential`. If the profile
has more than one, pass `--credential <key>`. Refresh the stored subject token
later with:

```shell
openshell provider update custom-api --from-oidc-token
```

This copies the current OIDC access token and expiry from the active gateway
login. This requires an active named gateway that was registered for OIDC. If
the stored gateway access token is expired and a refresh token is available, the
CLI refreshes it before storing the provider credential. It does not store the
OIDC refresh token in the provider.

Provider profile metadata is available for known provider types. Provider profile
network policy is gateway opt-in:

```shell
openshell settings set --global --key providers_v2_enabled --value true
```

Without `providers_v2_enabled=true`, attached provider profiles do not contribute
network policy to the sandbox. Static credential endpoint binding remains active
in either mode.

When `providers_v2_enabled=true`, `--from-existing` uses profile-backed
discovery instead of the legacy provider registry. The requested `--type` must
have a built-in or imported provider profile with a `discovery` section. If no
matching profile exists, the CLI returns an error instead of falling back to
legacy discovery.

Update a custom provider profile after exporting it, editing its endpoints,
binaries, or credential metadata, and preserving the exported `resource_version`:

```shell
openshell provider profile export my-api -o yaml > my-api-profile.yaml
openshell provider profile update my-api -f my-api-profile.yaml
```

Import remains create-only and fails if the profile ID already exists. Use
`provider profile update <id>` for existing custom profiles. Built-in profiles are
read-only. The target ID must match the profile ID in the file. Update accepts
one file at a time and rejects stale resource versions. When
`providers_v2_enabled=true`, updated profile policy applies to all provider
instances of that type on the next sandbox config sync.

> **Warning**
>
> Static credentials require a built-in or imported provider profile. Profiles
> normally define at least one endpoint. An endpointless profile requires an
> explicit `credential_binding.provider` on a sandbox policy endpoint. OpenShell
> does not activate static credentials from a profileless provider because it
> cannot determine which credential definition applies.

## Manage Providers

List, inspect, update, and delete providers from the active gateway.

List all providers:

```shell
openshell provider list
```

Use `-o json` or `-o yaml` for machine-readable output:

```shell
openshell provider list -o json
openshell provider list -o yaml
```

Structured output includes provider metadata (`id`, `name`, `type`), credential key names, config key names, labels, creation timestamp, resource version, and credential expiration times. Only credential and config keys are exposed, never values, preventing accidental credential leakage in logs or output. For details on how credentials are injected into sandboxes, refer to [Credential Injection](#how-credential-injection-works).

Inspect a provider:

```shell
openshell provider get my-claude
```

Update a provider's credentials:

```shell
openshell provider update my-claude --from-existing
```

Set or clear a credential expiry timestamp:

```shell
openshell provider update my-graph \
  --credential MS_GRAPH_ACCESS_TOKEN="$MS_GRAPH_ACCESS_TOKEN" \
  --credential-expires-at MS_GRAPH_ACCESS_TOKEN=1767225600000
```

Use `0` as the timestamp to clear expiry for a credential key.

## Credential Refresh

Provider refresh stores non-injectable refresh material separately from the
provider's current credential values. The gateway can mint OAuth2 refresh-token
tokens, OAuth2 client credentials tokens, Google service account JWT tokens, and
AWS STS temporary credentials, then write the current access token back to the
provider record for sandbox injection.

Configure refresh metadata for one injectable credential key:

```shell
openshell provider refresh configure my-graph \
  --credential-key MS_GRAPH_ACCESS_TOKEN \
  --strategy oauth2-client-credentials \
  --material tenant_id="$TENANT_ID" \
  --material client_id="$CLIENT_ID" \
  --secret-material-env client_secret=CLIENT_SECRET \
  --credential-expires-at 1767225600000
```

Pass secret material with `--secret-material-env KEY[=ENVVAR]` (`ENVVAR`
defaults to `KEY`): the CLI reads the value from its own environment, so the
secret never appears in the host process table the way an expanded
`--material KEY="$VALUE"` argument would, and `KEY` is automatically marked
secret. Keep non-secret material on `--material`; `--secret-material-key KEY`
still marks a key supplied through `--material` as secret.

Check refresh status:

```shell
openshell provider refresh status my-graph
```

Delete refresh metadata for a credential:

```shell
openshell provider refresh delete my-graph \
  --credential-key MS_GRAPH_ACCESS_TOKEN
```

Force a gateway-managed refresh for one credential:

```shell
openshell provider refresh rotate my-graph --credential-key MS_GRAPH_ACCESS_TOKEN
```

### AWS STS

AWS STS refresh requires `providers_v2_enabled=true`. The gateway calls
`sts:AssumeRole` and writes three short-lived credentials (`AWS_ACCESS_KEY_ID`,
`AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`) to the provider record atomically.
The `aws` and `aws-s3` profiles declare `AWS_SECRET_ACCESS_KEY` and
`AWS_SESSION_TOKEN` as `additional_outputs` of the `AWS_ACCESS_KEY_ID` refresh,
so all three credentials are gateway-minted. Create the provider with
`--runtime-credentials` — no placeholder credential is needed.

```shell
openshell settings set --global --key providers_v2_enabled --value true --yes

openshell provider create --name my-aws --type aws-s3 --runtime-credentials

openshell provider refresh configure my-aws \
  --credential-key AWS_ACCESS_KEY_ID \
  --strategy aws-sts-assume-role \
  --material role_arn="arn:aws:iam::123456789012:role/SandboxS3Writer" \
  --material session_name="openshell-sandbox"

openshell provider refresh rotate my-aws --credential-key AWS_ACCESS_KEY_ID
```

The gateway resolves its own AWS credentials using the default credential chain
(instance role, IRSA, ECS task role, environment variables). For gateways not
running on AWS, provide explicit IAM keys via refresh material:

```shell
openshell provider refresh configure my-aws \
  --credential-key AWS_ACCESS_KEY_ID \
  --strategy aws-sts-assume-role \
  --material role_arn="arn:aws:iam::123456789012:role/SandboxS3Writer" \
  --material aws_access_key_id="$AWS_ACCESS_KEY_ID" \
  --secret-material-env aws_secret_access_key=AWS_SECRET_ACCESS_KEY
```

Pass the long-lived secret with `--secret-material-env` so the CLI reads it
from its own environment instead of expanding it into a process argument,
where it would be visible in the host process table.

For temporary source credentials (AWS SSO or a prior `AssumeRole`), also pass a
session token with `--secret-material-env aws_session_token=AWS_SESSION_TOKEN`.
It requires the `aws_access_key_id` and `aws_secret_access_key` pair.

Use the generic `aws` profile type for multi-service access and scope endpoints
via sandbox network policy. Use `aws-s3` for S3-specific endpoint rules.

The proxy re-signs requests using SigV4 before forwarding to AWS. Both curl and
Python boto3 are supported.

External refresh systems should continue to push new current credentials through
`openshell provider update`. The `--credential-expires-at` option works for
static credentials, externally refreshed credentials, and gateway-managed
refresh strategies.

Delete a provider:

```shell
openshell provider delete my-claude
```

## Attach Providers to Sandboxes

Pass one or more `--provider` flags when creating a sandbox:

```shell
openshell sandbox create --provider my-claude --provider my-github -- claude
```

Each `--provider` flag attaches one provider. The sandbox receives eligible
credentials from every attached provider as placeholders at runtime. Each
static credential resolves only for endpoints in that provider's profile, or
for explicitly bound sandbox policy endpoints when the profile is endpointless.
Profile-managed providers also contribute provider-generated network policy
entries when `providers_v2_enabled` is enabled at the gateway. When the setting
is disabled, endpoint binding still applies, but provider-generated policy does
not.

> **Warning**
>
> Legacy provider attachment is fixed at sandbox creation time. Providers v2 adds
> `openshell sandbox provider attach` and `openshell sandbox provider detach` for
> running sandboxes. See [Providers v2](/sandboxes/providers-v2#attach-and-detach-providers)
> for runtime attach and detach behavior.

### Auto-Discovery Shortcut

When `providers_v2_enabled=false` and the trailing command in
`openshell sandbox create` is a recognized tool name (`claude`, `codex`, or
`opencode`), the CLI auto-creates the required provider from your local
credentials if one does not already exist. You do not need to create the
provider separately:

```shell
openshell sandbox create -- claude
```

This detects `claude` as a known tool, finds your `ANTHROPIC_API_KEY`, creates
a provider, attaches it to the sandbox, and launches Claude Code.

Providers v2 disables command-derived provider inference. When
`providers_v2_enabled=true`, create or import the provider profile, create the
provider instance, and pass `--provider <name>` explicitly.

## How Credential Injection Works

The agent process inside the sandbox never sees real credential values. At
startup, OpenShell replaces each credential with an opaque placeholder token in
the agent's environment. When the agent sends an HTTP request containing a
placeholder, the proxy resolves it immediately before forwarding the request.

Static credential resolution has two independent authorization boundaries:

1. Network policy must allow the calling binary and request destination.
2. The credential binding must include the request host, port, and path. Profile
   endpoints provide the binding by default. An endpointless profile can use a
   sandbox policy endpoint that names the attached provider instance through
   `credential_binding.provider`.

Both checks must pass. A provider profile endpoint does not grant network access
unless provider policy composition or the sandbox's own policy allows the
request. A plain sandbox policy endpoint does not grant credential use unless
the profile already covers it or the endpoint explicitly binds an endpointless
provider.

Endpoint binding applies whether `providers_v2_enabled` is enabled or disabled.
The setting controls provider policy composition only. Every static credential
declared by a provider receives the complete endpoint set from that provider's
profile, or the explicitly bound sandbox policy endpoints for an endpointless
profile.

Credential resolution requires the proxy to handle the request as HTTP. Raw
`tls: skip` and non-HTTP tunnels remain opaque and do not support credential
rewrite. Refer to [Providers v2](/sandboxes/providers-v2#understand-static-credential-endpoint-binding)
for endpoint matching and migration guidance.

### Supported injection locations

The proxy resolves credential placeholders in the following parts of an HTTP request:

| Location                  | How the agent uses it                                                                                                       | Example                               |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| Header value              | Agent reads `$API_KEY` from env and places it in a header.                                                                  | `Authorization: Bearer <placeholder>` |
| Header value (Basic auth) | Agent base64-encodes `user:<placeholder>` in an `Authorization: Basic` header. The proxy decodes, resolves, and re-encodes. | `Authorization: Basic <base64>`       |
| Query parameter value     | Agent places the placeholder in a URL query parameter.                                                                      | `GET /api?key=<placeholder>`          |
| URL path segment          | Agent builds a URL with the placeholder in the path. Supports concatenated patterns.                                        | `POST /bot<placeholder>/sendMessage`  |
| Supported request body    | An inspected REST endpoint opts in with `request_body_credential_rewrite: true`.                                            | `{"api_key":"<placeholder>"}`         |
| WebSocket text message    | A REST or WebSocket endpoint opts in with `websocket_credential_rewrite: true`.                                             | `{"token":"<placeholder>"}`           |
| AWS SigV4 signing         | An endpoint configures `credential_signing`, and the proxy signs with the endpoint-bound AWS credentials.                   | `credential_signing: sigv4`           |

The proxy does not rewrite cookies, response content, unsupported request
bodies, or WebSocket binary frames.

### Fail-closed behavior

If policy allows a request but the credential binding does not include the
request endpoint, the proxy rejects the request with HTTP 403 and the
`credential_endpoint_mismatch` reason. It emits a denied activity event and a
security finding without recording the secret, placeholder, environment key, or
query string.

Unknown, malformed, expired, or otherwise unresolved placeholders also fail
closed instead of being forwarded to the upstream service.

### Inspect an Endpoint Binding

Export the profile used by a provider to inspect its credential boundary:

```shell
openshell provider profile export github -o yaml
```

For the built-in GitHub profile, `GITHUB_TOKEN` and `GH_TOKEN` can resolve for
the profile's `api.github.com:443` and `github.com:443` endpoints. Even if a
sandbox policy allows `uploads.example.com:443`, sending either placeholder
there returns `credential_endpoint_mismatch`.

For a custom service, define the credential in a custom provider profile. Put
stable endpoints in the profile, or leave the profile endpointless and bind
each concrete provider instance from sandbox policy. Refer to [Provider Profiles](/sandboxes/providers-v2#provider-profiles) for the profile workflow
and schema.

## Supported Provider Types

The following provider types are supported.

| Type          | Environment Variables Injected                                                  | Typical Use                                                                                                                                                                                                                                   |
| ------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `anthropic`   | `ANTHROPIC_API_KEY`                                                             | Anthropic API                                                                                                                                                                                                                                 |
| `aws-bedrock` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, `AWS_REGION` | AWS Bedrock InvokeModel via a translating bridge. Today the router does not inject any auth header; the configured `BEDROCK_BASE_URL` upstream is expected to handle auth itself. Refer to [Inference Routing](/sandboxes/inference-routing). |
| `claude`      | `ANTHROPIC_API_KEY`, `CLAUDE_API_KEY`                                           | Claude Code, Anthropic API                                                                                                                                                                                                                    |
| `codex`       | `OPENAI_API_KEY`                                                                | OpenAI Codex                                                                                                                                                                                                                                  |
| `copilot`     | `COPILOT_GITHUB_TOKEN`, `GH_TOKEN`, `GITHUB_TOKEN`                              | GitHub Copilot CLI                                                                                                                                                                                                                            |
| `deepinfra`   | `DEEPINFRA_API_KEY`                                                             | DeepInfra inference API                                                                                                                                                                                                                       |
| `generic`     | User-defined                                                                    | Legacy credential storage. Import an endpoint-bearing custom profile for credentials attached to a sandbox.                                                                                                                                   |
| `github`      | `GITHUB_TOKEN`, `GH_TOKEN`                                                      | GitHub API and `gh` CLI. Refer to [GitHub Sandbox](/get-started/tutorials/github-sandbox).                                                                                                                                                    |
| `gitlab`      | `GITLAB_TOKEN`, `GLAB_TOKEN`, `CI_JOB_TOKEN`                                    | GitLab API, `glab` CLI                                                                                                                                                                                                                        |
| `nvidia`      | `NVIDIA_API_KEY`                                                                | NVIDIA API Catalog                                                                                                                                                                                                                            |
| `openai`      | `OPENAI_API_KEY`                                                                | Any OpenAI-compatible endpoint. Set `--config OPENAI_BASE_URL` to point to the provider. Refer to [Inference Routing](/sandboxes/inference-routing).                                                                                          |
| `opencode`    | `OPENCODE_API_KEY`, `OPENROUTER_API_KEY`, `OPENAI_API_KEY`                      | OpenCode                                                                                                                                                                                                                                      |

> **Note**
>
> `ANTHROPIC_API_KEY` is an API key from [console.anthropic.com](https://console.anthropic.com), not a subscription token. Subscription users must generate a separate API key from the Anthropic Console.

> **Tip**
>
> For a service not listed above, import a custom provider profile that declares
> its credential environment variables and endpoints. Use the imported profile
> ID as the provider `--type`.

## Supported Inference Providers

The following providers have been tested with `inference.local`. Any provider that exposes an OpenAI-compatible API works with the `openai` type. Set `--config OPENAI_BASE_URL` to the provider's base URL and `--credential OPENAI_API_KEY` to your API key.

| Provider                 | Name             | Type               | Base URL                                          | API Key Variable                                                     |
| ------------------------ | ---------------- | ------------------ | ------------------------------------------------- | -------------------------------------------------------------------- |
| AWS Bedrock (via bridge) | `bedrock-bridge` | `aws-bedrock`      | Operator-supplied `BEDROCK_BASE_URL`              | None at router level (bridge holds creds)                            |
| NVIDIA API Catalog       | `nvidia-prod`    | `nvidia`           | `https://integrate.api.nvidia.com/v1`             | `NVIDIA_API_KEY`                                                     |
| Anthropic                | `anthropic-prod` | `anthropic`        | `https://api.anthropic.com`                       | `ANTHROPIC_API_KEY`                                                  |
| Google Vertex AI         | `vertex-prod`    | `google-vertex-ai` | Regional, global, or multi-region Vertex endpoint | `GOOGLE_VERTEX_AI_TOKEN` or `GOOGLE_VERTEX_AI_SERVICE_ACCOUNT_TOKEN` |
| Baseten                  | `baseten`        | `openai`           | `https://inference.baseten.co/v1`                 | `OPENAI_API_KEY`                                                     |
| Bitdeer AI               | `bitdeer`        | `openai`           | `https://api-inference.bitdeer.ai/v1`             | `OPENAI_API_KEY`                                                     |
| DeepInfra                | `deepinfra`      | `deepinfra`        | `https://api.deepinfra.com/v1/openai`             | `DEEPINFRA_API_KEY`                                                  |
| Groq                     | `groq`           | `openai`           | `https://api.groq.com/openai/v1`                  | `OPENAI_API_KEY`                                                     |
| Ollama (local)           | `ollama`         | `openai`           | `http://host.openshell.internal:11434/v1`         | `OPENAI_API_KEY`                                                     |
| LM Studio (local)        | `lmstudio`       | `openai`           | `http://host.openshell.internal:1234/v1`          | `OPENAI_API_KEY`                                                     |

Refer to your provider's documentation for the correct base URL, available models, and API key setup. For the Vertex-specific auth flows and config keys, refer to [Google Vertex AI](/providers/google-vertex-ai). To configure inference routing, refer to [Inference Routing](/sandboxes/inference-routing).

## Next Steps

Explore related topics:

* To manage workspace access for providers, refer to [Manage Workspaces and Access](/sandboxes/manage-workspaces).
* To control what the agent can access, refer to [Policies](/sandboxes/policies).
* To use the base sandbox container, refer to [Sandboxes](/sandboxes/manage-sandboxes#base-sandbox-container).
* To view the complete field reference for the policy YAML, refer to the [Policy Schema Reference](/reference/policy-schema).