---
path: onboarding/devops-onboarding/service-accounts-and-tokens.mdx
title: Service accounts and API tokens
sidebar_position: 2
slug: service-accounts-and-tokens
pagination_next: null
pagination_prev: null
description: >-
  How to create a Passwork service account for automation, configure a minimal-permission role,
  generate and store the API token pair, and implement token rotation for CI/CD pipelines.
keywords:
  - Passwork
  - service account
  - API token
  - access token
  - refresh token
  - token rotation
  - automation
  - CI/CD
  - least privilege
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## Why you shouldn't use a personal account

Using a personal user account for CI/CD or automation creates several problems:

- The token is tied to an employee — if they leave, all integrations break
- Personal account permissions are often broader than what the script needs
- Actions appear in the audit log under the person's name, not the pipeline's
- Revoking access requires deleting or changing the personal account

A dedicated **service account** separates automation from human identities, follows least privilege, and makes the audit trail clear.

---

## Step 1 — Create a service account role

Before creating the account, create a role that grants only what automation needs.

1. Go to **Settings → User management → Roles**.
2. Click **Create role** and name it (e.g. `CI/CD service account` or `Rotation bot`).
3. Enable **only** the following permissions:
   - **Use API** (required for token generation)
   - No access to user management, system settings, LDAP, SSO, or vault type management
4. Click **Create**.

Directory access (which vaults and folders the service account can read or write) is configured separately when the service account is created

:::tip One role per pipeline type
If you have multiple automation use cases (deploy bot, rotation script, audit exporter), create separate roles with different permission sets. This limits damage scope if a token is compromised.
:::

---

## Step 2 — Create the service account 

1. Go to **Settings → User management → Users**.
2. Click **Create user**.
3. Use a clearly identifiable login, e.g. `svc-cicd-production` or `svc-rotation-bot`.
4. Assign the role created in Step 1 and groups, if necessary.
6. Click **Create**.

If using LDAP, create a dedicated LDAP service account in your directory and map it to Passwork. Do not reuse an AD service account that has other system rights.

---

## Step 3 — Grant vault access

The service account must be explicitly added to the vaults and folders it needs to access.

1. Open the service account profile.
2. Set the necessary access levels for the corresponding vaults listed on the **Access rights** tab.

| Use case | Minimum access level |
|----------|---------------------|
| CI/CD pipeline (read secrets for deployment) | **Read only** |
| Rotation script (update secret values) | **Read and edit** |
| Audit / reporting script | **Read only** |
| Migration / bulk import | **Full access** on target vault |

Use folder-level access if the service account only needs a subset of the vault.

---

## Step 4 — Generate the token pair

1. Open the service account profile
2. Open the **API tokens** menu in the rightside panel and click **Create API token**.
5. Copy **both** the `accessToken` and `refreshToken` immediately — they are shown only once.

<ImageComponent
  src="/img/assets/srvc.png"
  alt="Service account page"
  format="regular"
/>

:::danger Store tokens securely
Never store tokens in source code, .env files committed to repositories, or CI/CD job logs. Use your CI/CD platform's encrypted secret storage (GitHub Secrets, GitLab CI/CD with masked variables, HashiCorp Vault, AWS Secrets Manager, etc.).
:::

---

## Token pair lifecycle

Passwork API uses two tokens with different lifetimes:

| Token | Typical lifetime | Purpose |
|-------|-----------------|---------|
| `accessToken` | Minutes to hours | Added to every API request as `Authorization: Bearer` |
| `refreshToken` | Days to weeks | Used to obtain a new token pair when access token expires |

When `accessToken` expires, the API returns HTTP 401 with code `accessTokenExpired`. The integration then calls the refresh endpoint and updates both tokens.

The Python connector handles this automatically. For shell scripts using `passwork-cli`, the CLI also handles token refresh transparently when `PASSWORK_REFRESH_TOKEN` is provided.

---

## Token rotation strategy

Regular rotation of the service account's token pair reduces the risk from token leakage.

**Recommended token lifetimes by use case:**

| Use case | accessToken lifetime | refreshToken lifetime |
|----------|----------------------|------------------------|
| CI/CD job (ephemeral) | 15–60 minutes | 1 day |
| Always-on service (monitoring, rotation bot) | 1–4 hours | 30 days |
| Manual/scheduled script | 1 hour | 7 days |

**Rotating tokens via API:**

Three endpoints are available (see [API token rotation](https://passwork.pro/tech-guides/api-and-integrations/api-token-rotation/) for full reference):

<Tabs className="tabs-container">
  <TabItem className="tab-item-container" value="pair" label="Rotate full pair">

  ```shell
  curl -s --request POST \
    --url "https://passwork.example.com/api/v1/sessions/refresh" \
    --header 'Content-Type: application/json' \
    --header 'X-Response-Format: raw' \
    --header "Authorization: Bearer $PASSWORK_TOKEN" \
    --data "{\"refreshToken\": \"$PASSWORK_REFRESH_TOKEN\"}" | jq .
  ```
  </TabItem>
  <TabItem className="tab-item-container" value="access-only" label="Rotate access token only">

  ```shell
  curl -s --request POST \
    --url "https://passwork.example.com/api/v1/sessions/refresh-access-token" \
    --header 'Content-Type: application/json' \
    --header 'X-Response-Format: raw' \
    --data "{\"accessToken\": \"$PASSWORK_TOKEN\"}" | jq .
  ```
  </TabItem>
</Tabs>

---

## The token storage paradox

Passwork is the secret store — but you need a credential to access it. Where do you store the Passwork token?

**Recommended approaches:**

| Environment | Where to store Passwork tokens |
|-------------|-------------------------------|
| CI/CD (GitHub Actions, GitLab) | Platform's encrypted secret storage (masked variables) |
| Kubernetes workloads | Kubernetes Secret, ideally populated by an external secret operator |
| Long-running services | Environment variable injected at startup via a higher-trust secret store or config management |
| Developer workstations | .env file not committed to VCS, or OS keychain |

The key principle: Passwork tokens are bootstrap credentials. They live one level above the secrets they protect. They need strong protection — not as strong as a cloud provider root key, but stronger than an application database password.
