Providers

View as Markdown

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.

Provider profiles define provider credentials, policy, and refresh behavior. See Profiles for the profile format and custom profile workflow.

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

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:

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:

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:

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:

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:

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.

--from-existing uses profile-backed discovery. 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.

Create a provider whose profile requires no static credentials without a credential source:

openshell provider create --name public-pypi --type pypi

Provider creation rejects profileless types. For a custom GitLab deployment, import a profile with the deployment’s endpoints and then create an instance using that profile ID. Existing profileless provider records remain usable, but OpenShell does not create new ones.

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

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. Updated profile policy applies to all provider instances of that type on the next sandbox config sync.

Delete one or more custom provider profiles by ID:

openshell provider profile delete custom-api custom-alt

When a multi-profile delete fails for one entry, the CLI reports that profile’s failure and continues with the remaining IDs. The command exits with an error after it attempts every requested deletion if any entry failed.

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:

openshell provider list

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

openshell provider list -o json
openshell provider list -o yaml

Structured list output is an envelope with providers and next_page_token fields. Each provider includes 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. Pass the returned token to --page-token to continue. For details on how credentials are injected into sandboxes, refer to Credential Injection.

Inspect a provider:

openshell provider get my-claude

Update a provider’s credentials:

openshell provider update my-claude --from-existing

Set or clear a credential expiry timestamp:

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:

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:

openshell provider refresh status my-graph

Delete refresh metadata for a credential:

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

Force a gateway-managed refresh for one credential:

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

AWS STS

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.

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:

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:

openshell provider delete my-claude

Delete multiple providers by listing their names in one command:

openshell provider delete my-claude my-github

When a multi-provider delete fails for one entry, the CLI reports that provider’s failure and continues with the remaining names. The command exits with an error after it attempts every requested deletion if any entry failed.

Attach Providers to Sandboxes

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

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. Endpoint binding independently limits where each static credential can be resolved.

Use --provider to attach providers when creating a sandbox. To change the providers attached to a running sandbox, use openshell sandbox provider attach and openshell sandbox provider detach. See Profiles for details.

Auto-Discovery Shortcut

When the trailing command in openshell sandbox create maps to an available profile, the CLI auto-creates the required provider from local profile discovery if one does not already exist. You do not need to create the provider separately:

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.

If the inferred type has no built-in or imported profile, creation fails. Import a custom profile first or pass an existing provider with --provider <name>.

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.

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 Profiles for endpoint matching and migration guidance.

Supported injection locations

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

LocationHow the agent uses itExample
Header valueAgent 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 valueAgent places the placeholder in a URL query parameter.GET /api?key=<placeholder>
URL path segmentAgent builds a URL with the placeholder in the path. Supports concatenated patterns.POST /bot<placeholder>/sendMessage
Supported request bodyAn inspected REST endpoint opts in with request_body_credential_rewrite: true.{"api_key":"<placeholder>"}
WebSocket text messageA REST or WebSocket endpoint opts in with websocket_credential_rewrite: true.{"token":"<placeholder>"}
AWS SigV4 signingAn 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:

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 Profiles for the profile workflow and schema.

Supported Provider Types

The following provider types are supported.

TypeEnvironment Variables InjectedTypical Use
anthropicANTHROPIC_API_KEYAnthropic API
aws-bedrockAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_REGIONDeclarative Bedrock credential shape. The built-in profile does not grant a bridge or AWS endpoint; use an endpoint-bearing profile for direct access.
claudeANTHROPIC_API_KEY, CLAUDE_API_KEYClaude Code, Anthropic API
codexOPENAI_API_KEYOpenAI Codex
copilotCOPILOT_GITHUB_TOKEN, GH_TOKEN, GITHUB_TOKENGitHub Copilot CLI
deepinfraDEEPINFRA_API_KEYDeepInfra inference API
githubGITHUB_TOKEN, GH_TOKENGitHub API and gh CLI. Refer to GitHub Sandbox.
nvidiaNVIDIA_API_KEYNVIDIA API Catalog
openaiOPENAI_API_KEYPublic OpenAI API. Use a custom endpoint-bearing profile for another OpenAI-compatible host.

ANTHROPIC_API_KEY is an API key from console.anthropic.com, not a subscription token. Subscription users must generate a separate API key from the Anthropic Console.

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.

Inference Provider Access

Attach an inference provider to each sandbox that needs it and configure the workload to call the provider’s native endpoint. The workload, not OpenShell, selects the model and request timeout.

ProviderBuilt-in profileNative base URLCredential variable
OpenAIopenaihttps://api.openai.com/v1OPENAI_API_KEY
Anthropicanthropichttps://api.anthropic.comANTHROPIC_API_KEY
NVIDIA API Catalognvidiahttps://integrate.api.nvidia.com/v1NVIDIA_API_KEY
DeepInfradeepinfrahttps://api.deepinfra.com/v1/openaiDEEPINFRA_API_KEY
Google Vertex AIgoogle-vertex-aiRegion and model dependentGOOGLE_VERTEX_AI_TOKEN or GOOGLE_VERTEX_AI_SERVICE_ACCOUNT_TOKEN

An OpenAI-compatible protocol does not make the built-in openai profile safe for an arbitrary host. Baseten, Bitdeer, Groq, Ollama, LM Studio, self-hosted NIM, and other alternate endpoints need a custom profile that declares the actual host, port, credential, and allowed binaries. See Provider-backed Inference for complete examples and migration guidance.

Next Steps

Explore related topics: