---
title: External Credential Providers
subtitle: Connect Bitwarden, 1Password, Azure Key Vault, or your own vault API
slug: cloud/managing-credentials/external-providers
---
Instead of copying secrets into Skyvern, you can point Skyvern at your existing vault and it pulls credentials at runtime. If your organization already manages secrets in a dedicated vault, connect it as a credential source and reference items directly from workflow parameters.
External providers are configured per-organization. Once connected, any workflow in the organization can reference credentials from that provider.
## Choosing a provider
| Source | Credential types | Setup | Best for |
|--------|-----------------|-------|----------|
| **Skyvern** (default) | Password, Credit Card, Secret | None (built in) | Most users, fastest setup |
| **Bitwarden** | Password, Credit Card, Identity | Credential parameter config | Teams already using Bitwarden (enterprise) |
| **1Password** | Password, Credit Card | Settings page setup | Teams with 1Password service accounts |
| **Azure Key Vault** | Password (with optional TOTP) | Settings page setup | Enterprise Azure environments |
| **Webhook (Custom API)** | Password, Credit Card | Settings page setup | Organizations with custom vaults |
You can mix sources within the same workflow. For example, one Login block can use Skyvern-stored credentials while another uses Azure Key Vault.
---
## Bitwarden
Bitwarden integration is available on the **enterprise plan**. Contact [sales@skyvern.com](mailto:sales@skyvern.com) for access.
Works with hosted Bitwarden and the self-hosted [Vaultwarden](https://github.com/dani-garcia/vaultwarden) fork. Supports passwords, credit cards, and identity data (SSN, address, phone numbers).
Make sure your Bitwarden account is on `bitwarden.com`, not `bitwarden.eu`. The EU instance uses a different API that Skyvern does not currently support.
### Cloud setup
Log into Bitwarden, navigate to **Admin Console**, and ensure you have an organization created.
In your organization, click **New → Create a collection**. Name it something identifiable (e.g., "Skyvern Credentials"). Skip this step if you already have a collection ready.
Go to the **Access** tab on your collection. This step requires coordination with the Skyvern enterprise team, who will configure access on their end. Contact [sales@skyvern.com](mailto:sales@skyvern.com) to get started.
Click into the collection and find the collection UUID in the URL bar.
In the Skyvern workflow editor, click **Parameters → Add Parameter → Credential Parameter** and select the **Bitwarden** tab. Enter your **Collection ID** and optionally an **Item ID** to target a specific vault item.
### Configuration options
| Field | Description |
|-------|------------|
| **Collection ID** | The UUID of your Bitwarden collection (found in the URL when viewing the collection) |
| **Item ID** | Target a specific vault item. Leave blank to use URL matching instead. |
| **URL Parameter Key** | Match credentials by the target URL. Useful when the same workflow runs against different sites. |
### Identity data
For identity fields (SSN, address, phone numbers), specify an **Identity Key** and a comma-separated list of **Identity Fields** (e.g., `ssn, address, phone`) in the Credential Parameter configuration panel.
Skyvern integrates with self-hosted Bitwarden-compatible services like Vaultwarden using the Bitwarden CLI server as a bridge:
```text
Skyvern → bw serve (CLI Server) → Vaultwarden
```
**Environment variables:**
```bash
# Skyvern Bitwarden Configuration
SKYVERN_AUTH_BITWARDEN_ORGANIZATION_ID=your-org-id-here
SKYVERN_AUTH_BITWARDEN_MASTER_PASSWORD=your-master-password-here
SKYVERN_AUTH_BITWARDEN_CLIENT_ID=user.your-client-id-here
SKYVERN_AUTH_BITWARDEN_CLIENT_SECRET=your-client-secret-here
# Vaultwarden Configuration
BW_HOST=https://your-vaultwarden-server.com
BW_CLIENTID=${SKYVERN_AUTH_BITWARDEN_CLIENT_ID}
BW_CLIENTSECRET=${SKYVERN_AUTH_BITWARDEN_CLIENT_SECRET}
BW_PASSWORD=${SKYVERN_AUTH_BITWARDEN_MASTER_PASSWORD}
# CLI Server Configuration
BITWARDEN_SERVER=http://localhost
BITWARDEN_SERVER_PORT=8002
```
Start the CLI server with Docker Compose:
```bash
docker-compose up -d bitwarden-cli
```
Verify it's running:
```bash
curl http://localhost:8002/status
```
---
## 1Password
Connects via a [service account token](https://developer.1password.com/docs/service-accounts/get-started/). A service account is an API-only identity that accesses vault items without a human login. Supports passwords and credit cards.
### One-time setup
In your 1Password admin console, go to **Developer > Service Accounts** and create a new service account. Grant it access to the vault that contains the credentials Skyvern needs.
In Skyvern, go to **Settings** and find the **1Password** card.
Paste the service account token from the previous step.
Click **Update**. The status indicator turns **Active** once the token is validated.
If the status does not turn Active, verify that your service account token has access to the target vault and has not expired.
### Using in a workflow
In the workflow editor, add a **Credential Parameter** and select **1Password** as the source. Provide the **Vault ID** and **Item ID**. You can find both IDs in the URL when viewing an item in the 1Password web app.
Credit cards from 1Password need a custom text field named **"Expire Date"**, **"Expiry Date"**, or **"Expiration Date"** in `MM/YYYY` or `MM/YY` format. 1Password does not expose the native expiration field through its API, so Skyvern reads this custom text field instead.
---
## Azure Key Vault
Pulls credentials stored as Azure secrets. Supports passwords with optional TOTP.
### One-time setup
Go to **Settings** and find the **Azure** card.
Provide your **Tenant ID**, **Client ID**, and **Client Secret**.
Click **Update**. Skyvern will use these credentials to access your vault.
### Using in a workflow
In the workflow editor, add a **Credential Parameter** and select **Azure Key Vault** as the source. Provide the vault name and the **secret names** that store the username, password, and optionally a TOTP secret. Enter the secret names, not the values themselves.
For example, if your vault stores secrets named `salesforce-username`, `salesforce-password`, and `salesforce-totp`, enter those three names in the corresponding fields.
---
## Webhook (Custom API)
Connect your own HTTP API as a credential backend. Skyvern calls your API to create, retrieve, and delete credentials, so sensitive data stays in your infrastructure.
### API contract
Your service must implement three endpoints. All requests include an `Authorization: Bearer {API_TOKEN}` header.
**Create credential**
```http
POST {API_BASE_URL}
Authorization: Bearer {API_TOKEN}
Content-Type: application/json
```
The request body depends on the credential type. Your API must handle all three:
```json
{
"name": "Salesforce Login",
"type": "password",
"username": "user@example.com",
"password": "secure_password",
"totp": "JBSWY3DPEHPK3PXP",
"totp_type": "authenticator"
}
```
The `totp` and `totp_type` fields are optional. `totp_type` can be `"authenticator"`, `"email"`, `"text_message"`, or `"none"`.
```json
{
"name": "Corporate Visa",
"type": "credit_card",
"card_holder_name": "Jane Doe",
"card_number": "4111111111111111",
"card_exp_month": "12",
"card_exp_year": "2025",
"card_cvv": "123",
"card_brand": "visa"
}
```
```json
{
"name": "Stripe API Key",
"type": "secret",
"secret_value": "sk_live_abc123",
"secret_label": "api-key"
}
```
The `secret_label` field is optional.
Response (all types):
```json
{
"id": "cred_123456"
}
```
**Get credential**
```http
GET {API_BASE_URL}/{credential_id}
Authorization: Bearer {API_TOKEN}
```
Return the same fields that were sent during creation (minus `name`). Include `type` so Skyvern knows how to parse the response.
**Delete credential**
```http
DELETE {API_BASE_URL}/{credential_id}
Authorization: Bearer {API_TOKEN}
```
Response: HTTP 200
### Setup
Go to **Settings** and find the **Custom Credential Service** card.
Provide the **API Base URL** and **API Token** for your credential service.
Click **Update Configuration**. The status indicator turns **Active** once the configuration is saved.
```python
from fastapi import FastAPI, HTTPException, Depends, Header
from pydantic import BaseModel
from typing import Optional
import uuid
app = FastAPI()
credentials_store = {}
class CreateCredentialRequest(BaseModel):
name: str
type: str # "password", "credit_card", or "secret"
# Password fields
username: Optional[str] = None
password: Optional[str] = None
totp: Optional[str] = None
totp_type: Optional[str] = None
# Credit card fields
card_holder_name: Optional[str] = None
card_number: Optional[str] = None
card_exp_month: Optional[str] = None
card_exp_year: Optional[str] = None
card_cvv: Optional[str] = None
card_brand: Optional[str] = None
# Secret fields
secret_value: Optional[str] = None
secret_label: Optional[str] = None
class CredentialResponse(BaseModel):
id: str
def verify_token(authorization: str = Header(...)):
if not authorization.startswith("Bearer "):
raise HTTPException(401, "Invalid authorization header")
token = authorization.split("Bearer ")[1]
if token != "your_expected_api_token":
raise HTTPException(401, "Invalid API token")
@app.post("/api/v1/credentials", response_model=CredentialResponse)
async def create_credential(
request: CreateCredentialRequest,
_: None = Depends(verify_token)
):
credential_id = f"cred_{uuid.uuid4().hex[:12]}"
credentials_store[credential_id] = request.model_dump()
return CredentialResponse(id=credential_id)
@app.get("/api/v1/credentials/{credential_id}")
async def get_credential(
credential_id: str,
_: None = Depends(verify_token)
):
if credential_id not in credentials_store:
raise HTTPException(404, "Credential not found")
return credentials_store[credential_id]
@app.delete("/api/v1/credentials/{credential_id}")
async def delete_credential(
credential_id: str,
_: None = Depends(verify_token)
):
if credential_id not in credentials_store:
raise HTTPException(404, "Credential not found")
del credentials_store[credential_id]
return {"status": "deleted"}
```
For self-hosted Skyvern deployments, set these environment variables instead of using the Settings UI:
```bash
CREDENTIAL_VAULT_TYPE=custom
CUSTOM_CREDENTIAL_API_BASE_URL=https://credentials.company.com/api/v1/credentials
CUSTOM_CREDENTIAL_API_TOKEN=your_api_token_here
```
Restart Skyvern after setting these variables.
### Troubleshooting
| Problem | What to check |
|---------|--------------|
| Status stays Inactive | Verify the API base URL is a valid URL and the API token is not empty. The configuration is validated on save but does not make a live request to your server. |
| Credentials not created | Review your API logs for auth errors. Ensure the response includes an `id` field. Skyvern expects HTTP 200 for all operations. |
| Credentials not retrieved | Ensure the GET response includes all required fields for the credential type (`username` and `password` for passwords, all card fields for credit cards, `secret_value` for secrets). |
| Env config not working | Restart Skyvern after setting variables. Verify `CREDENTIAL_VAULT_TYPE=custom` is set and both URL and token are provided. The default vault type is `bitwarden`, so this variable must be explicitly set. |
---
Built-in credential storage, security model, and quick start
Store login details with optional 2FA
Configure credential parameters in the workflow editor