feat: add custom credential service (#4129)
Co-authored-by: Stanislav Novosad <stas@skyvern.com>
This commit is contained in:
203
fern/credentials/custom-credential-service.mdx
Normal file
203
fern/credentials/custom-credential-service.mdx
Normal file
@@ -0,0 +1,203 @@
|
||||
---
|
||||
title: Custom Credential Service
|
||||
subtitle: Integrate your own HTTP API for credential management
|
||||
slug: credentials/custom-credential-service
|
||||
---
|
||||
|
||||
Skyvern supports integrating with custom HTTP APIs for credential management, allowing you to use your existing credential infrastructure instead of third-party services.
|
||||
|
||||
## Overview
|
||||
|
||||
The custom credential service feature enables Skyvern to store and retrieve credentials from external HTTP APIs. This is perfect for organizations that:
|
||||
|
||||
- Have existing credential management systems
|
||||
- Need to maintain credentials in their own infrastructure
|
||||
- Want to integrate with proprietary credential vaults
|
||||
- Require custom authentication flows
|
||||
|
||||
## API Contract
|
||||
|
||||
Your custom credential service must implement these HTTP endpoints:
|
||||
|
||||
### Create Credential
|
||||
```http
|
||||
POST {API_BASE_URL}
|
||||
Authorization: Bearer {API_TOKEN}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "My Credential",
|
||||
"type": "password",
|
||||
"username": "user@example.com",
|
||||
"password": "secure_password",
|
||||
"totp": "JBSWY3DPEHPK3PXP",
|
||||
"totp_type": "authenticator"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"id": "cred_123456"
|
||||
}
|
||||
```
|
||||
|
||||
### Get Credential
|
||||
```http
|
||||
GET {API_BASE_URL}/{credential_id}
|
||||
Authorization: Bearer {API_TOKEN}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"type": "password",
|
||||
"username": "user@example.com",
|
||||
"password": "secure_password",
|
||||
"totp": "JBSWY3DPEHPK3PXP",
|
||||
"totp_type": "authenticator"
|
||||
}
|
||||
```
|
||||
|
||||
### Delete Credential
|
||||
```http
|
||||
DELETE {API_BASE_URL}/{credential_id}
|
||||
Authorization: Bearer {API_TOKEN}
|
||||
```
|
||||
|
||||
**Response:** HTTP 200 (empty body acceptable)
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables (Self-hosted)
|
||||
|
||||
Set these environment variables in your `.env` file:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
### Organization Configuration (Cloud)
|
||||
|
||||
Use the Skyvern API to configure per-organization:
|
||||
|
||||
```http
|
||||
POST /api/v1/credentials/custom_credential/create
|
||||
Authorization: Bearer {SKYVERN_API_KEY}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"config": {
|
||||
"api_base_url": "https://credentials.company.com/api/v1/credentials",
|
||||
"api_token": "your_api_token_here"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### UI Configuration
|
||||
|
||||
1. Navigate to **Settings** → **Custom Credential Service**
|
||||
2. Enter your API Base URL and API Token
|
||||
3. Click **Test Connection** to verify connectivity
|
||||
4. Click **Update Configuration** to save
|
||||
|
||||
## Example Implementation
|
||||
|
||||
Here's a minimal example using FastAPI:
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI, HTTPException, Depends, Header
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
import uuid
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# In-memory storage (use a real database in production)
|
||||
credentials_store = {}
|
||||
|
||||
class CreateCredentialRequest(BaseModel):
|
||||
name: str
|
||||
type: str # "password" or "credit_card"
|
||||
username: Optional[str] = None
|
||||
password: Optional[str] = None
|
||||
totp: Optional[str] = None
|
||||
totp_type: 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"}
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- API tokens are stored encrypted in the database
|
||||
- Bearer tokens are transmitted over HTTPS only
|
||||
- Frontend masks sensitive tokens in the UI
|
||||
- API credentials are never logged in plaintext
|
||||
- Implement proper rate limiting and authentication in your API
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Test Fails
|
||||
|
||||
1. Verify API base URL is correct and accessible
|
||||
2. Check that API token is valid
|
||||
3. Check firewall and network connectivity
|
||||
4. Note: Connection test only verifies basic connectivity - 404/405 responses are considered successful if the server is reachable
|
||||
|
||||
### Credentials Not Created
|
||||
|
||||
1. Review API logs for authentication errors
|
||||
2. Verify request format matches expected schema
|
||||
3. Ensure API returns `id` in response
|
||||
|
||||
### Environment Configuration Not Working
|
||||
|
||||
1. Restart Skyvern after setting environment variables
|
||||
2. Verify `CREDENTIAL_VAULT_TYPE=custom` is set
|
||||
3. Check both URL and token are provided
|
||||
|
||||
## Limitations
|
||||
|
||||
- Connection testing verifies network connectivity and basic API reachability but not full endpoint implementation
|
||||
- API must support all required endpoints (no partial implementation)
|
||||
- Token rotation requires manual reconfiguration
|
||||
- No built-in credential synchronization between vaults
|
||||
@@ -58,6 +58,7 @@ If you have your own password manager, Skyvern can integrate with it. Skyvern ca
|
||||
**Supported password manager types**:
|
||||
- Bitwarden
|
||||
- 1Password Integration
|
||||
- Custom Credential Service (HTTP API)
|
||||
|
||||
**Coming Soon**:
|
||||
- LastPass Integration
|
||||
@@ -88,6 +89,13 @@ Contact [Skyvern Support](mailto:support@skyvern.com) if you want access to the
|
||||
>
|
||||
(coming soon) Securely manage your passwords with LastPass
|
||||
</Card>
|
||||
<Card
|
||||
title="Custom Credential Service"
|
||||
icon="api"
|
||||
href="/credentials/custom-credential-service"
|
||||
>
|
||||
Integrate your own HTTP API for credential management
|
||||
</Card>
|
||||
<Card
|
||||
title="Keeper Integration"
|
||||
icon="lock-keyhole"
|
||||
|
||||
@@ -131,6 +131,8 @@ navigation:
|
||||
path: credentials/totp.mdx
|
||||
- page: Bitwarden
|
||||
path: credentials/bitwarden.mdx
|
||||
- page: Custom Credential Service
|
||||
path: credentials/custom-credential-service.mdx
|
||||
- section: Browser Sessions (Beta)
|
||||
contents:
|
||||
- page: Introduction
|
||||
|
||||
Reference in New Issue
Block a user