> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.datalab.to/llms.txt
> Use this file to discover all available pages before exploring further.

# Security Best Practices

> Keep your Datalab integration secure with these best practices.

Follow these practices to keep your Datalab integration secure in production.

## Two-Factor Authentication

Two-factor authentication (TOTP) is available for all Datalab accounts. Enable it from the [Security page](https://www.datalab.to/app/security) in the dashboard.

### Enrolling

1. Navigate to [datalab.to/app/security](https://www.datalab.to/app/security)
2. Click **Set up two-factor authentication**
3. Scan the QR code with an authenticator app (Google Authenticator, Authy, 1Password, etc.)
4. Enter the 6-digit code to confirm enrollment
5. Save the one-time recovery codes in a secure location — they are shown only once

After enrollment, you will be prompted for a TOTP code on each new login session.

### Recovery Codes

If you lose access to your authenticator app, use a recovery code to sign in. Each code is single-use. You can regenerate a fresh set from the Security page once you have re-authenticated.

### Team-wide MFA Enforcement

Team plan admins can require two-factor authentication for all team members:

1. Go to **Settings → Team** and find the Two-Factor Authentication section
2. Toggle on **Require two-factor authentication**
3. Members who aren't enrolled yet are automatically redirected to the Security page to enroll before they can access the app
4. API key authentication is not affected by team MFA policy

<Warning>
  Admins must be enrolled in two-factor authentication themselves before they can enforce it for the team.
</Warning>

## API Key Management

### Store keys in environment variables

Never hardcode API keys in source code. Use environment variables:

```bash theme={null}
export DATALAB_API_KEY="your-api-key"
```

```python theme={null}
# The SDK reads DATALAB_API_KEY automatically
from datalab_sdk import DatalabClient
client = DatalabClient()  # Uses env var
```

<Warning>
  Never commit API keys to version control. Add `.env` files to your `.gitignore`.
</Warning>

### Use per-key spend limits

Create separate API keys for different environments and set spend limits on each:

* **Development key** — low spend limit for testing
* **Staging key** — moderate limit for integration testing
* **Production key** — appropriate limit for your expected usage

Manage keys at [datalab.to/app/keys](https://www.datalab.to/app/keys).

### Rotate keys regularly

If you suspect a key has been compromised:

1. Create a new API key at [datalab.to/app/keys](https://www.datalab.to/app/keys)
2. Update your application to use the new key
3. Revoke the old key

<Tip>
  Create the new key before revoking the old one to avoid downtime.
</Tip>

## Webhook Security

### Always use HTTPS

Configure your webhook endpoint to use HTTPS. Webhook payloads contain request data that should be encrypted in transit.

### Verify webhook signatures

Always verify the webhook signature before processing the payload:

```python theme={null}
import hashlib
import hmac
from fastapi import FastAPI, Request, HTTPException

app = FastAPI()
WEBHOOK_SECRET = "your-webhook-secret"

@app.post("/webhook")
async def handle_webhook(request: Request):
    body = await request.body()
    signature = request.headers.get("X-Webhook-Signature")

    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        body,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(signature, expected):
        raise HTTPException(status_code=401, detail="Invalid signature")

    # Process the webhook payload
    payload = await request.json()
    return {"status": "ok"}
```

### Handle duplicate events

Webhook deliveries may be retried on 5xx errors or timeouts. Use the `request_id` field to deduplicate:

```python theme={null}
processed_ids = set()  # Use a database in production

@app.post("/webhook")
async def handle_webhook(request: Request):
    payload = await request.json()
    request_id = payload["request_id"]

    if request_id in processed_ids:
        return {"status": "already processed"}

    processed_ids.add(request_id)
    # Process the payload
```

<Warning>
  Do not log webhook secrets or full webhook payloads containing sensitive document data.
</Warning>

## Data Handling

### Results expiration

Conversion results are automatically deleted from Datalab servers **one hour** after processing completes. Retrieve and store results in your own infrastructure promptly.

### Data retention consent

You can control whether your documents are used to improve Datalab's models. This is an opt-in setting configurable in your team settings. Teams that opt in receive discounted rates.

### Minimize data exposure

* Only send documents that need to be processed — avoid sending unnecessary files
* Use `page_range` to process only the pages you need rather than entire documents
* Download and delete results as soon as they're available

## Network Security

### For on-premises deployments

* Place the Datalab container behind a reverse proxy with TLS termination
* Restrict network access to the container's port (8000) to trusted clients only
* The on-premises container does not require API key authentication by default — implement authentication at the network or reverse proxy level
* See [On-Premises Overview](/docs/on-prem/overview) for deployment details

### IP restrictions

For additional security, consider restricting API access to known IP addresses using your infrastructure's firewall or WAF rules.

## Next Steps

<CardGroup cols={2}>
  <Card title="Webhooks" icon="bell" href="/platform/webhooks">
    Configure and verify webhook signatures
  </Card>

  <Card title="API Limits" icon="gauge" href="/docs/common/limits">
    Understand rate limits and quotas
  </Card>

  <Card title="Billing" icon="credit-card" href="/platform/billing">
    Manage spend limits and usage
  </Card>

  <Card title="On-Premises" icon="server" href="/docs/on-prem/overview">
    Self-hosted deployment security
  </Card>
</CardGroup>
