API key providers
Add vendor credentials, configure Bedrock authentication, and verify provider access.
Most paid APIs are API-key providers: OpenAI, Anthropic, Groq, Mistral, DeepSeek, and other providers marked as API-key providers. You paste the upstream secret; DurinDoor stores it on a connection and sends it as Authorization: Bearer or the header that provider declares (x-api-key for Anthropic-style transports).
Open Dashboard, then Providers, then the provider. Add API Key (or Add Connection) opens the form.
Pick the provider card. Providers that support both OAuth and API keys offer both methods on their page.
Give the connection a name. The dialog fills the first unused name in the main, main-2, main-3 sequence. Reopening after a successful add clears secrets and provider-specific fields; a background refresh while the dialog is open does not.
Paste the key. Cloudflare Workers AI and Snowflake Cortex also require an account id (name|apiKey|accountId on bulk lines). Azure wants endpoint, API version, deployment, and optional organization. Google Programmable Search needs cx.
Set priority if you already have another key for this provider. Lower numbers run first under fill-first selection. Optional: default model, proxy pool, per-connection proxy URL.
Save, then send a request using one of the connection's models. A duplicate provider, credential, and name is rejected with HTTP 409. Validation probes stop after 10 seconds; connection tests stop after 15 seconds.
ollama-local and other noAuth providers may omit the key. Compatible nodes still require a value even when the upstream ignores it; use a placeholder such as local-dev-key. See OpenAI-compatible nodes.
Bulk add accepts one key per line (name|sk-key, or a bare key that gets an auto name). Bulk create is create-only: a name collision never overwrites a saved key.
Amazon Bedrock credentials
Bedrock is the one API-key provider that accepts three credential shapes. Pick the region where your models are enabled, then fill in exactly one of these in the AWS Credentials block:
| Mode | What you enter | Refresh |
|---|---|---|
| Profile (SSO) | AWS Profile only, API Key left empty | Automatic, the AWS SDK re-resolves the profile |
| Static AWS keys | AWS secret access key in API Key, key id in Access Key ID, Session Token for temporary ASIA... keys | None, paste new keys when they expire |
| Bedrock API key | The Bedrock API key in API Key on its own | None |
A profile takes precedence over everything else, and static AWS keys are selected by the presence of an Access Key ID. A connection that only carries an API Key keeps behaving exactly as before.
Profile mode is the recommended path. Name a profile from ~/.aws/config, save the connection with an empty API Key, then run aws sso login --profile <name>. DurinDoor never reads or stores the SSO token: the AWS SDK resolves it from the local token cache on each request and refreshes it on expiry, so the saved connection holds nothing secret. source_profile role chaining and credential_process profiles resolve the same way. Only the named profile is used: if it is missing or fails to resolve, the request fails with HTTP 401 and never falls back to the server's own AWS credentials (environment variables, ECS or instance role).
Saving a profile-only connection skips the usual API-key requirement, so POST /api/providers and the validate probe both accept an empty key. The profile is resolved as the user running DurinDoor, and a profile can run a credential_process command, so setting one is limited to operators (the dashboard or the CLI token). An application API key gets HTTP 403 from POST /api/providers, PUT /api/providers/<id>, and POST /api/providers/validate when the request names a profile. A profile name must match ^[A-Za-z0-9_.:-]{1,64}$; anything else gets HTTP 400.
Check, Test and the health monitor verify profile and static-key connections with a SigV4-signed Converse call that carries no messages. AWS checks the signature before the body, so a ValidationException means the credentials work and no inference runs. An AccessDeniedException also counts as valid credentials: AWS accepted the key and IAM denied the model. The IAM secret access key is never sent as a bearer token. A Bedrock API key connection keeps the bearer probe.
Temporary AWS keys beginning with ASIA require a session token. A missing token is rejected with 401. The session token is encrypted separately and is not returned in provider responses.
When editing, leave the session-token field blank to keep the saved token. Changing or clearing the Access Key ID also clears it. Entering a new API key clears the saved profile after validation. For an expired SSO session, run aws sso login --profile <name> again.
Env fallbacks
Saved connections are the path you should use. A handful of executors still read process environment when a connection field is empty:
| Variable | Used when |
|---|---|
OPENAI_API_KEY | Azure executor, if the connection has no apiKey or accessToken. Not a generic OpenAI connection. |
AZURE_ENDPOINT, AZURE_API_VERSION, AZURE_DEPLOYMENT, AZURE_ORGANIZATION | Azure URL and headers when providerSpecificData omits them. API version default is 2024-10-01-preview. |
GITLAB_DUO_BASE_URL / GITLAB_BASE_URL | GitLab Duo origin; default https://gitlab.com. |
FIRECRAWL_API_KEY | Auto-configure for the Firecrawl web-fetch connection. |
CLI_DEVIN_BIN | Override Devin CLI binary discovery. |
WINDSURF_API_KEY | Devin CLI executor, if the connection has no key or token. |
CLIPROXYAPI_HOST / CLIPROXYAPI_PORT | CLIProxyAPI listen address. |
OAuth client overrides (GEMINI_OAUTH_CLIENT_ID, ANTIGRAVITY_OAUTH_CLIENT_ID, and their secrets) belong on Connecting accounts. The full operator list is Environment variables.
Scoping a DurinDoor API key to accounts
A DurinDoor client key (sk-...) can be limited to a subset of provider connections. An empty account scope means unrestricted: the key may use every reachable account. Assigning one or more connection ids opts into the restriction. Clearing the list restores the unrestricted default.
Details, deletion guards, and the HTTP shape live in API key scoping. Deleting a connection that is the last scoped account for a key is rejected with HTTP 409 API_KEY_SCOPE_WOULD_BROADEN so the key cannot silently become unrestricted.
Test a saved key from the provider page. Connection tests stop after 15 seconds. Custom URLs still go through the outbound SSRF guard. Hidden registry providers cannot be created through this form; POST /api/providers returns Invalid provider.
Priority is per provider. Drag accounts on the provider page to change their order. Fill-first selection then uses that order. See Connecting accounts for how that interacts with account fallback.
Edit Connection does not display the stored secret. To rotate a vendor key, create its replacement at the vendor, update the connection, and verify a request before revoking the old credential.
Proxy fields on the add dialog are optional: connectionProxyEnabled, connectionProxyUrl, connectionNoProxy, and proxyPoolId. __none__ means no pool. A bad pool id is rejected before the connection is written.
google-pse requires cx (Programmable Search Engine id) in provider-specific data. Without it, create returns 400.
If a probe passes but chat fails, check model entitlement and deployment names. Bedrock AccessDeniedException can mean the credentials are valid but IAM denies that model; a passing credential probe does not grant inference permission.