mirror of
https://github.com/Skyvern-AI/skyvern.git
synced 2026-04-28 11:40:32 +00:00
516 lines
16 KiB
Text
516 lines
16 KiB
Text
---
|
|
title: Handle 2FA
|
|
subtitle: Configure two-factor authentication for automated logins
|
|
description: Configure two-factor authentication for Skyvern automations using TOTP secrets, pushed verification codes, pull-based endpoints, or magic links. Supports Bitwarden TOTP integration.
|
|
slug: credentials/handle-2fa
|
|
keywords:
|
|
- TOTP
|
|
- 2FA
|
|
- totp_identifier
|
|
- totp_url
|
|
- authenticator
|
|
- email code
|
|
- SMS code
|
|
- magic link
|
|
- send_totp_code
|
|
- verification
|
|
---
|
|
|
|
Many websites require two-factor authentication (2FA) during login. Skyvern supports multiple 2FA methods to handle these flows automatically.
|
|
|
|
---
|
|
|
|
## Choose your method
|
|
|
|
Select the method that matches how you receive verification codes:
|
|
|
|
| Scenario | Recommended Method |
|
|
|----------|-------------------|
|
|
| You have the TOTP secret key | [Store TOTP secret](#method-1-store-totp-secret): Skyvern generates codes |
|
|
| Codes sent to email/SMS you can forward | [Push codes to Skyvern](#method-2-push-codes-to-skyvern) |
|
|
| Codes sent to a system you control | [Skyvern pulls from your endpoint](#method-3-skyvern-pulls-from-your-endpoint) |
|
|
| Passwordless/magic link auth | [Magic links](#method-4-magic-links) |
|
|
| Using Bitwarden with TOTP | [Password manager integration](#password-manager-totp) |
|
|
|
|
---
|
|
|
|
## Method 1: Store TOTP secret
|
|
|
|
**Best for:** Sites where you have access to the TOTP secret (the setup QR code or manual key).
|
|
|
|
When you enable 2FA on a website, you're typically shown a QR code or a secret key. Store this secret with your credential, and Skyvern generates valid codes automatically.
|
|
|
|
<CodeGroup>
|
|
```python Python
|
|
import os
|
|
from skyvern import Skyvern
|
|
|
|
client = Skyvern(api_key=os.getenv("SKYVERN_API_KEY"))
|
|
|
|
credential = await client.create_credential(
|
|
name="Acme Portal Login",
|
|
credential_type="password",
|
|
credential={
|
|
"username": "user@example.com",
|
|
"password": "secure_password",
|
|
"totp": "JBSWY3DPEHPK3PXP", # Base32 secret from QR code
|
|
"totp_type": "authenticator",
|
|
},
|
|
)
|
|
```
|
|
|
|
```typescript TypeScript
|
|
import { SkyvernClient } from "@skyvern/client";
|
|
|
|
const client = new SkyvernClient({
|
|
apiKey: process.env.SKYVERN_API_KEY,
|
|
});
|
|
|
|
const credential = await client.createCredential({
|
|
name: "Acme Portal Login",
|
|
credential_type: "password",
|
|
credential: {
|
|
username: "user@example.com",
|
|
password: "secure_password",
|
|
totp: "JBSWY3DPEHPK3PXP",
|
|
totp_type: "authenticator",
|
|
},
|
|
});
|
|
```
|
|
|
|
```bash cURL
|
|
curl -X POST "https://api.skyvern.com/v1/credentials" \
|
|
-H "x-api-key: $SKYVERN_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"name": "Acme Portal Login",
|
|
"credential_type": "password",
|
|
"credential": {
|
|
"username": "user@example.com",
|
|
"password": "secure_password",
|
|
"totp": "JBSWY3DPEHPK3PXP",
|
|
"totp_type": "authenticator"
|
|
}
|
|
}'
|
|
```
|
|
</CodeGroup>
|
|
|
|
### TOTP types
|
|
|
|
| Type | Description |
|
|
|------|-------------|
|
|
| `authenticator` | Standard TOTP codes (Google Authenticator, Authy, etc.) |
|
|
| `email` | Codes sent via email that you'll push to Skyvern |
|
|
| `text` | Codes sent via SMS that you'll push to Skyvern |
|
|
|
|
<Tip>
|
|
Skyvern generates TOTP codes using standard 30-second windows. If the current code has less than 20 seconds remaining, Skyvern automatically uses the next code to ensure successful entry.
|
|
</Tip>
|
|
|
|
### Finding your TOTP secret
|
|
|
|
Most sites show the secret when you set up 2FA:
|
|
|
|
1. Go to your account's security settings
|
|
2. Click "Set up authenticator app"
|
|
3. Look for "Can't scan the QR code?" or "Manual entry"
|
|
4. Copy the secret key (usually Base32 format like `JBSWY3DPEHPK3PXP`)
|
|
|
|
<Note>
|
|
If you've already set up 2FA and don't have the secret, you may need to disable and re-enable 2FA to see the secret again. Contact [support@skyvern.com](mailto:support@skyvern.com) for help.
|
|
</Note>
|
|
|
|
---
|
|
|
|
## Method 2: Push codes to Skyvern
|
|
|
|
**Best for:** Codes sent to email or SMS that you can programmatically forward.
|
|
|
|
When your automation encounters a 2FA prompt, Skyvern polls for codes that you push via API. Your email or SMS forwarding system sends codes to Skyvern as they arrive.
|
|
|
|
### Step 1: Set up code forwarding
|
|
|
|
Configure your email or SMS to forward verification codes to Skyvern. Common approaches:
|
|
|
|
- **Email:** Gmail filter + Zapier webhook
|
|
- **SMS:** Twilio webhook to your server
|
|
- **Email:** AWS SES + Lambda function
|
|
|
|
<AccordionGroup>
|
|
<Accordion title="How to set up Email Forwarding with Zapier?">
|
|
|
|
This setup requires a Zapier Pro plan account.
|
|
|
|
<Steps>
|
|
<Step title="Create a Zapier Zap">
|
|
{/* TODO: Replace with actual video */}
|
|
<Frame>
|
|
<video
|
|
autoPlay
|
|
muted
|
|
loop
|
|
playsInline
|
|
className="rounded-xl"
|
|
src="/images/zapier-forwarding-setup.mp4"
|
|
></video>
|
|
</Frame>
|
|
|
|
1. Go to [zapier.com](https://zapier.com/app/home) and create a new Zap
|
|
2. In the newly created Zap draft, click the "Trigger" button
|
|
3. Click **Email by Zapier**
|
|
4. In the Email "Setup", pick **New Inbound Email** in the Trigger event selection. Click **Continue**
|
|
5. In Email "Configure", create an email address which will be used to forward emails for TOTP codes. Click **Continue**
|
|
6. Click the "Action" button and add **Webhooks by Zapier**
|
|
7. In the Setup, choose **POST** under the Action event selection. Click **Continue**
|
|
8. In the "Configure", set up these fields to make a POST request to Skyvern's TOTP API:
|
|
- **URL:** `https://api.skyvern.com/v1/credentials/totp`
|
|
- **Payload Type:** `json`
|
|
- **Data:**
|
|
- `totp_identifier`: choose **Raw To Email** after clicking the "+" sign
|
|
- `content`: choose **Body Plain** after clicking the "+" sign
|
|
- `source`: `email`
|
|
- **Headers:**
|
|
- `x-api-key`: your Skyvern API key
|
|
9. Click **Continue**
|
|
</Step>
|
|
<Step title="Add forwarding email and create a filter in Gmail">
|
|
Go to Gmail Settings → Forwarding and POP/IMAP → click **Add a forwarding address** → enter the Zapier email address you created. Complete any verification steps.
|
|
|
|
Then go to **Filters and Blocked Addresses**. Click **Create a new filter** and set up a filtering rule for your TOTP (2FA/MFA) emails. Click **Create filter**, check **Forward it to**, pick the Zapier email address, and update the filter.
|
|
|
|
<Frame>
|
|
<img src="/images/totp/create_email_forwarding.png" alt="Gmail forwarding filter" width="400"/>
|
|
</Frame>
|
|
</Step>
|
|
<Step title="Test it end to end">
|
|
Forward any previous TOTP email to the Zapier email address you created.
|
|
|
|
In Zapier, under the "Test" of the Webhooks action, send a request to test it out. If successful, you should see a "A request was sent to Webhooks by Zapier" message.
|
|
</Step>
|
|
</Steps>
|
|
|
|
</Accordion>
|
|
<Accordion title="How to set up SMS Forwarding with Twilio?">
|
|
|
|
Use a virtual phone number service like [Twilio](https://www.twilio.com/en-us/docs/usage/tutorials/how-to-use-your-free-trial-account) or [Plivo](https://www.plivo.com/) to receive SMS codes and forward them to Skyvern.
|
|
|
|
<Steps>
|
|
<Step title="Set up a Twilio phone number">
|
|
Create a Twilio account and provision a phone number. This number will receive the SMS verification codes.
|
|
</Step>
|
|
<Step title="Create a Twilio Function to forward codes">
|
|
In your Twilio console, create a new Function that forwards incoming SMS to Skyvern's TOTP API:
|
|
|
|
```javascript
|
|
// Twilio Function
|
|
exports.handler = async function(context, event, callback) {
|
|
const axios = require('axios');
|
|
|
|
await axios.post('https://api.skyvern.com/v1/credentials/totp', {
|
|
totp_identifier: event.To, // Your Twilio phone number
|
|
content: event.Body,
|
|
source: 'phone'
|
|
}, {
|
|
headers: {
|
|
'x-api-key': context.SKYVERN_API_KEY,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
});
|
|
|
|
return callback(null, new Twilio.Response());
|
|
};
|
|
```
|
|
|
|
Add your `SKYVERN_API_KEY` as an environment variable in the Twilio Function configuration.
|
|
</Step>
|
|
<Step title="Configure the webhook">
|
|
In your Twilio phone number settings, set the **A Message Comes In** webhook to point to your Twilio Function URL.
|
|
</Step>
|
|
<Step title="Test it">
|
|
Send a test SMS to your Twilio number and verify the code appears in Skyvern:
|
|
|
|
```bash
|
|
curl -X GET "https://api.skyvern.com/v1/credentials/totp?totp_identifier=YOUR_TWILIO_NUMBER" \
|
|
-H "x-api-key: $SKYVERN_API_KEY"
|
|
```
|
|
</Step>
|
|
</Steps>
|
|
|
|
</Accordion>
|
|
</AccordionGroup>
|
|
|
|
### Step 2: Start the run with a TOTP identifier
|
|
|
|
When running your login, include a `totp_identifier` that matches what you'll use when pushing codes:
|
|
|
|
<CodeGroup>
|
|
```python Python
|
|
result = await client.login(
|
|
credential_type="skyvern",
|
|
url="https://portal.example.com/login",
|
|
credential_id="cred_xyz789",
|
|
totp_identifier="user@example.com", # Must match when pushing code
|
|
)
|
|
```
|
|
|
|
```bash cURL
|
|
curl -X POST "https://api.skyvern.com/v1/run/tasks/login" \
|
|
-H "x-api-key: $SKYVERN_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"credential_type": "skyvern",
|
|
"url": "https://portal.example.com/login",
|
|
"credential_id": "cred_xyz789",
|
|
"totp_identifier": "user@example.com"
|
|
}'
|
|
```
|
|
</CodeGroup>
|
|
|
|
### Step 3: Push the code when received
|
|
|
|
When the verification code arrives, push it to Skyvern:
|
|
|
|
<CodeGroup>
|
|
```python Python
|
|
await client.send_totp_code(
|
|
totp_identifier="user@example.com",
|
|
content="Your verification code is 123456", # Full email/SMS body
|
|
source="email",
|
|
)
|
|
```
|
|
|
|
```typescript TypeScript
|
|
await client.sendTotpCode({
|
|
totp_identifier: "user@example.com",
|
|
content: "Your verification code is 123456",
|
|
source: "email",
|
|
});
|
|
```
|
|
|
|
```bash cURL
|
|
curl -X POST "https://api.skyvern.com/v1/credentials/totp" \
|
|
-H "x-api-key: $SKYVERN_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"totp_identifier": "user@example.com",
|
|
"content": "Your verification code is 123456",
|
|
"source": "email"
|
|
}'
|
|
```
|
|
</CodeGroup>
|
|
|
|
<Note>
|
|
If `content` is longer than 10 characters, Skyvern's AI extracts the verification code automatically. You can send the full email or SMS body without parsing it yourself.
|
|
</Note>
|
|
|
|
|
|
---
|
|
|
|
## Method 3: Skyvern pulls from your endpoint
|
|
|
|
**Best for:** Environments where you control the system receiving 2FA codes and can expose them via an HTTP endpoint.
|
|
|
|
Instead of pushing codes to Skyvern, you implement an endpoint that Skyvern polls until a code is available.
|
|
|
|
### Step 1: Implement the endpoint
|
|
|
|
Your endpoint must accept POST requests and return the verification code:
|
|
|
|
**Request from Skyvern:**
|
|
```http
|
|
POST https://your-server.com/totp-webhook
|
|
x-skyvern-signature: <hmac-sha256-signature>
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"task_id": "tsk_123456"
|
|
}
|
|
```
|
|
|
|
**Expected response:**
|
|
```json
|
|
{
|
|
"task_id": "tsk_123456",
|
|
"verification_code": "123456"
|
|
}
|
|
```
|
|
|
|
### Step 2: Verify request signatures
|
|
|
|
Skyvern signs all requests using HMAC-SHA256 with your API key. Verify the signature to ensure requests are authentic:
|
|
|
|
```python
|
|
import hmac
|
|
import hashlib
|
|
|
|
def verify_skyvern_request(request, api_key: str) -> bool:
|
|
signature = request.headers.get("x-skyvern-signature")
|
|
payload = request.body # bytes
|
|
|
|
expected = hmac.new(
|
|
api_key.encode("utf-8"),
|
|
msg=payload,
|
|
digestmod=hashlib.sha256
|
|
).hexdigest()
|
|
|
|
return hmac.compare_digest(signature, expected)
|
|
```
|
|
|
|
### Step 3: Configure the login
|
|
|
|
Pass `totp_url` when running your login:
|
|
|
|
<CodeGroup>
|
|
```python Python
|
|
result = await client.login(
|
|
credential_type="skyvern",
|
|
url="https://portal.example.com/login",
|
|
credential_id="cred_xyz789",
|
|
totp_url="https://your-server.com/totp-webhook",
|
|
)
|
|
```
|
|
|
|
```bash cURL
|
|
curl -X POST "https://api.skyvern.com/v1/run/tasks/login" \
|
|
-H "x-api-key: $SKYVERN_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"credential_type": "skyvern",
|
|
"url": "https://portal.example.com/login",
|
|
"credential_id": "cred_xyz789",
|
|
"totp_url": "https://your-server.com/totp-webhook"
|
|
}'
|
|
```
|
|
</CodeGroup>
|
|
|
|
Skyvern polls your endpoint every 10 seconds until a code is returned or the timeout is reached.
|
|
|
|
---
|
|
|
|
## Method 4: Magic links
|
|
|
|
**Best for:** Passwordless authentication systems that send one-time login links.
|
|
|
|
When a site uses magic links instead of passwords, push the link to Skyvern:
|
|
|
|
<CodeGroup>
|
|
```python Python
|
|
await client.send_totp_code(
|
|
totp_identifier="user@example.com",
|
|
content="https://portal.example.com/login?token=abc123xyz",
|
|
source="email",
|
|
)
|
|
```
|
|
|
|
```bash cURL
|
|
curl -X POST "https://api.skyvern.com/v1/credentials/totp" \
|
|
-H "x-api-key: $SKYVERN_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"totp_identifier": "user@example.com",
|
|
"content": "https://portal.example.com/login?token=abc123xyz",
|
|
"source": "email"
|
|
}'
|
|
```
|
|
</CodeGroup>
|
|
|
|
<Note>
|
|
Skyvern automatically detects URLs and classifies them as magic links. The automation will navigate to the link to complete authentication.
|
|
</Note>
|
|
|
|
For magic link flows, structure your workflow in two parts:
|
|
|
|
1. **Trigger the magic link**: Navigate to login and enter email
|
|
2. **Complete login**: Use the magic link as the starting URL for the next step
|
|
|
|
---
|
|
|
|
## Password manager TOTP
|
|
|
|
If you store TOTP secrets in Bitwarden or 1Password, Skyvern can retrieve both the password and TOTP code in a single request.
|
|
|
|
### Bitwarden
|
|
|
|
Store your TOTP secret in Bitwarden's authenticator field:
|
|
|
|
1. Open the vault item in Bitwarden
|
|
2. Click "Authenticator Key (TOTP)"
|
|
3. Enter your TOTP secret or scan the QR code
|
|
4. Skyvern retrieves both password and TOTP when using this credential
|
|
|
|
**Supported TOTP formats:**
|
|
- Raw secret: `JBSWY3DPEHPK3PXP`
|
|
- otpauth URI: `otpauth://totp/Example:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example`
|
|
|
|
### 1Password
|
|
|
|
Store TOTP in 1Password's one-time password field:
|
|
|
|
1. Edit the login item in 1Password
|
|
2. Add a "One-Time Password" field
|
|
3. Enter the TOTP secret or scan the QR code
|
|
4. Reference the item in your Skyvern workflow
|
|
|
|
---
|
|
|
|
## Multi-field TOTP entry
|
|
|
|
Some sites split TOTP codes across multiple input fields (one digit per box). Skyvern handles this automatically:
|
|
|
|
1. Detects multi-field TOTP layouts
|
|
2. Enters the same code across all fields
|
|
3. Caches the code to prevent requesting a new one mid-entry
|
|
|
|
<Note>
|
|
No special configuration needed. Skyvern's AI recognizes multi-field TOTP inputs and handles them correctly.
|
|
</Note>
|
|
|
|
---
|
|
|
|
## Timeouts and polling
|
|
|
|
Skyvern waits for 2FA codes based on configurable timeouts:
|
|
|
|
| Setting | Default | Description |
|
|
|---------|---------|-------------|
|
|
| Polling interval | 10 seconds | How often Skyvern checks for new codes |
|
|
| Polling timeout | 15 minutes | Maximum wait time before failing |
|
|
|
|
If you're pushing codes, ensure your forwarding pipeline delivers codes within the timeout window.
|
|
|
|
---
|
|
|
|
## List recent codes
|
|
|
|
Debug your 2FA integration by listing recent codes received:
|
|
|
|
```bash
|
|
curl -X GET "https://api.skyvern.com/v1/credentials/totp?totp_identifier=user@example.com&limit=10" \
|
|
-H "x-api-key: $SKYVERN_API_KEY"
|
|
```
|
|
|
|
**Query parameters:**
|
|
|
|
| Parameter | Description |
|
|
|-----------|-------------|
|
|
| `totp_identifier` | Filter by identifier (email, phone, etc.) |
|
|
| `workflow_run_id` | Filter by specific workflow run |
|
|
| `otp_type` | Filter by type: `totp` or `magic_link` |
|
|
| `limit` | Number of records (default 50, max 200) |
|
|
|
|
<Note>
|
|
Skyvern only returns codes from the last 10 minutes (configurable via `TOTP_LIFESPAN_MINUTES`).
|
|
</Note>
|
|
|
|
---
|
|
|
|
## Next steps
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Store Credentials" icon="key" href="/credentials/store-credentials">
|
|
Set up your credential vault integration
|
|
</Card>
|
|
<Card title="Troubleshooting" icon="wrench" href="/credentials/troubleshooting-login">
|
|
Debug 2FA and login failures
|
|
</Card>
|
|
</CardGroup>
|