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

# Service Accounts API

> Manage machine identities for automated secret access

## Overview

Service accounts are machine identities designed for automated systems, CI/CD pipelines, and applications that need programmatic access to secrets.

## List Service Accounts

Retrieve all service accounts in an organization.

```bash theme={null}
GET /organizations/{organizationId}/service-accounts?includeAccessToSecrets={includeAccessToSecrets}
```

<ParamField path="organizationId" type="string" required>
  Organization ID
</ParamField>

<ParamField query="includeAccessToSecrets" type="boolean" default="false">
  Include detailed secret access information
</ParamField>

### Response

<ResponseField name="id" type="string" required>
  Service account unique identifier
</ResponseField>

<ResponseField name="organizationId" type="string" required>
  Parent organization ID
</ResponseField>

<ResponseField name="name" type="string" required>
  Service account name
</ResponseField>

<ResponseField name="creationDate" type="string" required>
  When service account was created
</ResponseField>

<ResponseField name="revisionDate" type="string" required>
  Last modification date
</ResponseField>

<ResponseField name="accessToSecrets" type="number">
  Number of secrets this service account can access
</ResponseField>

***

## Get Service Account

Retrieve a specific service account.

```bash theme={null}
GET /service-accounts/{id}
```

<ParamField path="id" type="string" required>
  Service account ID
</ParamField>

***

## Create Service Account

Create a new service account.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.bitwarden.com/organizations/{organizationId}/service-accounts" \
    -H "Authorization: Bearer {access_token}" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "CI/CD Pipeline"
    }'
  ```

  ```javascript JavaScript theme={null}
  const serviceAccount = await fetch(
    `https://api.bitwarden.com/organizations/${orgId}/service-accounts`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        name: 'GitHub Actions'
      })
    }
  ).then(r => r.json());
  ```
</CodeGroup>

### Request Body

<ParamField body="name" type="string" required>
  Service account name (e.g., "Production Deployment", "Terraform")
</ParamField>

<Info>
  Creating a service account may require additional seats on your Secrets Manager subscription.
</Info>

***

## Update Service Account

Update a service account's name.

```bash theme={null}
PUT /service-accounts/{id}
```

<ParamField path="id" type="string" required>
  Service account ID
</ParamField>

### Request Body

<ParamField body="name" type="string" required>
  New service account name
</ParamField>

***

## Delete Service Accounts

Delete one or more service accounts.

```bash theme={null}
POST /service-accounts/delete
```

<ParamField body="ids" type="array" required>
  Array of service account IDs to delete
</ParamField>

### Response

Returns results for each deletion:

```json theme={null}
{
  "data": [
    {
      "id": "sa-guid-1",
      "error": ""
    },
    {
      "id": "sa-guid-2",
      "error": "access denied"
    }
  ]
}
```

<Warning>
  Deleting a service account revokes all its access tokens. Active integrations will fail.
</Warning>

***

## Access Tokens

### List Access Tokens

Retrieve all access tokens for a service account.

```bash theme={null}
GET /service-accounts/{id}/access-tokens
```

<ParamField path="id" type="string" required>
  Service account ID
</ParamField>

### Response

<ResponseField name="id" type="string" required>
  Access token ID
</ResponseField>

<ResponseField name="name" type="string" required>
  Token name
</ResponseField>

<ResponseField name="creationDate" type="string" required>
  When token was created
</ResponseField>

<ResponseField name="expireAt" type="string">
  Token expiration date (null = no expiration)
</ResponseField>

<ResponseField name="revisionDate" type="string" required>
  Last modification date
</ResponseField>

***

### Create Access Token

Generate a new access token for a service account.

```bash theme={null}
POST /service-accounts/{id}/access-tokens
```

<ParamField path="id" type="string" required>
  Service account ID
</ParamField>

### Request Body

<ParamField body="name" type="string" required>
  Token name (e.g., "Production Token", "Staging Deploy")
</ParamField>

<ParamField body="encryptedPayload" type="string" required>
  Encrypted payload for the token
</ParamField>

<ParamField body="key" type="string" required>
  Encryption key
</ParamField>

<ParamField body="expireAt" type="string">
  Optional expiration date (ISO 8601 format)
</ParamField>

### Response

<ResponseField name="id" type="string" required>
  Token ID
</ResponseField>

<ResponseField name="clientSecret" type="string" required>
  The actual access token value (only returned once!)
</ResponseField>

<ResponseField name="name" type="string" required>
  Token name
</ResponseField>

<ResponseField name="creationDate" type="string" required>
  When token was created
</ResponseField>

<Warning>
  The `clientSecret` is only returned when creating the token. Store it securely - you cannot retrieve it again!
</Warning>

***

### Revoke Access Tokens

Revoke one or more access tokens.

```bash theme={null}
POST /service-accounts/{id}/access-tokens/revoke
```

<ParamField path="id" type="string" required>
  Service account ID
</ParamField>

<ParamField body="ids" type="array" required>
  Array of access token IDs to revoke
</ParamField>

***

## Access Management

Service accounts access secrets through projects. Grant access using access policies.

### Grant Project Access

Allow a service account to access a project:

```json theme={null}
{
  "serviceAccountAccessPolicies": [
    {
      "serviceAccountId": "sa-guid",
      "read": true,
      "write": false
    }
  ]
}
```

### Access Levels

* **Read**: Can fetch secrets
* **Write**: Can create/update secrets (typically not granted)

<Info>
  Most service accounts only need `read` access to fetch secrets for deployment.
</Info>

***

## Best Practices

### Naming Conventions

Use descriptive names that indicate purpose:

```
[System/Tool] - [Environment]

Examples:
GitHub Actions - Production
Terraform - Staging
Kubernetes - Development
Jenkins - CI Pipeline
```

### Security

1. **Least Privilege**: Only grant access to required projects
2. **Rotate Tokens**: Regenerate tokens periodically
3. **Set Expiration**: Use token expiration dates
4. **Monitor Usage**: Check event logs for suspicious activity
5. **Revoke Unused**: Delete service accounts and tokens no longer needed

### Token Management

1. **Name Descriptively**: Indicate token purpose and location
2. **Use Expiration**: Set expiration dates for production tokens
3. **Store Securely**: Use secret management in your CI/CD system
4. **One Token per System**: Don't share tokens across systems
5. **Revoke Immediately**: Remove compromised tokens right away

***

## Usage Examples

### CI/CD Integration (GitHub Actions)

```yaml theme={null}
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      
      - name: Fetch Secrets
        env:
          BW_SERVICE_TOKEN: ${{ secrets.BW_SERVICE_TOKEN }}
        run: |
          # Fetch secrets from Bitwarden
          SECRETS=$(curl -s "https://api.bitwarden.com/projects/${PROJECT_ID}/secrets" \
            -H "Authorization: Bearer ${BW_SERVICE_TOKEN}")
          
          # Export as environment variables
          echo "API_KEY=$(echo $SECRETS | jq -r '.data[] | select(.key=="API_KEY") | .value')" >> $GITHUB_ENV
      
      - name: Deploy
        run: ./deploy.sh
```

### Terraform Provider

```hcl theme={null}
provider "bitwarden" {
  access_token = var.bw_service_token
}

data "bitwarden_secret" "database_url" {
  key = "DATABASE_URL"
  project_id = var.project_id
}

resource "aws_db_instance" "main" {
  # Use secret in resource
  password = data.bitwarden_secret.database_url.value
}
```

### Docker Container

```dockerfile theme={null}
FROM node:18

WORKDIR /app

# Install Bitwarden CLI
RUN npm install -g @bitwarden/cli

# Copy startup script
COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
```

```bash theme={null}
#!/bin/bash
# entrypoint.sh

# Fetch secrets
export SECRETS=$(curl -s "https://api.bitwarden.com/projects/${PROJECT_ID}/secrets" \
  -H "Authorization: Bearer ${BW_SERVICE_TOKEN}")

# Set environment variables
export DATABASE_URL=$(echo $SECRETS | jq -r '.data[] | select(.key=="DATABASE_URL") | .value')

# Start application
npm start
```

### Kubernetes Secret Sync

```python theme={null}
import requests
import base64
from kubernetes import client, config

# Load k8s config
config.load_incluster_config()
v1 = client.CoreV1Api()

# Fetch secrets from Bitwarden
response = requests.get(
    f"https://api.bitwarden.com/projects/{project_id}/secrets",
    headers={"Authorization": f"Bearer {service_token}"}
)

secrets = response.json()['data']

# Create/update Kubernetes secret
secret_data = {}
for secret in secrets:
    secret_data[secret['key']] = base64.b64encode(
        secret['value'].encode()
    ).decode()

k8s_secret = client.V1Secret(
    metadata=client.V1ObjectMeta(name="app-secrets"),
    data=secret_data
)

v1.replace_namespaced_secret(
    name="app-secrets",
    namespace="default",
    body=k8s_secret
)
```

***

## Service Account Limits

Service account limits vary by plan:

| Plan         | Service Accounts                |
| ------------ | ------------------------------- |
| Free (trial) | 0                               |
| Teams        | Starts at 20, can purchase more |
| Enterprise   | Custom                          |

<Note>
  Service accounts count toward your Secrets Manager seat limit. Contact sales to add capacity.
</Note>
