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

# Create, rotate and revoke tokens

> Create personal access tokens and service account API keys, use them over REST and JDBC/ODBC, set an expiry, rotate, and revoke them.

This page is for everyone who connects to an e6data workspace over the API - through a BI tool, a notebook, a script, or an automated pipeline. It covers creating a token, using it, setting an expiry, rotating it, and revoking it.

## Choosing a token type

Pick the credential that matches the actor:

* A **person** acting under their own identity (Tableau, a notebook, a local script) → use a **Personal Access Token (PAT)**.
* A **machine or automated process** (CI/CD, Airflow, a service) → use a **Service Account API key**.

A PAT inherits your personal roles and is revoked when your account is deprovisioned, so it is **not** suitable for CI/CD. A service account is an independent identity that keeps working when team members change. For the full credential comparison and prefixes, see the canonical table in [Access tokens](/platform/tokens/pat-and-service-account-keys).

## Personal access tokens

A PAT authenticates the API **as you**. It inherits exactly the roles your user account has in the workspace.

### Create a personal access token

1. Open the **avatar menu** (top-right) and select **User settings**.
2. Go to the **Access tokens** tab.
3. Select **Create**.
4. Enter a **Comment** describing what the token is for (for example, `Tableau Desktop - Marketing`). This is required - 3 to 200 characters.
5. Set **Token Expiry**: enter a number of days (default 90, maximum 3650), or tick **Never expires**.
6. Select **Create**, then copy the token immediately.

<Warning>
  The token is shown only once. After you close the dialog, the full value cannot be retrieved again. If you lose it, create a new one and revoke the old one - there is no way to recover a lost token value.
</Warning>

### Use a personal access token

e6data's API accepts a token in either of two request headers. For a PAT the common convention is `Authorization: Bearer`, but both headers work:

| Header | Example |
| - | - |
| `Authorization: Bearer <token>` | `Authorization: Bearer e6pat_analytics_a1b2c3d4_xYz9…` |
| `X-API-Key: <token>` | `X-API-Key: e6pat_analytics_a1b2c3d4_xYz9…` |

REST (curl):

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -H "Authorization: Bearer e6pat_analytics_a1b2c3d4_xYz9…" \
  https://<workspace>.e6.run/api/v1/catalogs
```

For scripts, keep the token out of your shell history and source by reading it from an environment variable:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
export E6DATA_TOKEN="e6pat_analytics_a1b2c3d4_xYz9…"

curl -H "Authorization: Bearer $E6DATA_TOKEN" \
  https://<workspace>.e6.run/api/v1/catalogs
```

For JDBC/ODBC and BI tools (Tableau, Power BI, Looker, Metabase), use the e6data driver and supply your credentials as:

| Field | Value |
| - | - |
| Host | `<workspace>.e6.run` |
| Port | `443` |
| Username | your email address |
| Password | your PAT |
| Database / Catalog | your catalog name |

A typical JDBC connection string looks like:

```
jdbc:e6data://<workspace>.e6.run:443/<catalog>;schema=<schema>
```

The driver formats the auth header for you. If a generic BI tool sends your token as HTTP **Basic** auth instead, it won't be accepted - see [Troubleshooting](#troubleshooting).

### List and revoke your tokens

On **User settings → Access tokens** you can see all your tokens - comment, created date, and expiry (expired ones are flagged). Only metadata is shown; the token value is never displayed again. Select the trash icon next to a token and confirm to revoke it. Revocation takes effect immediately.

## Service accounts

A service account is a **machine identity** for automated and programmatic access. It cannot log into the Console - it authenticates only through its API keys, and it has its own role bindings. Because it isn't tied to a person, it keeps working when team members change.

### Create a service account

1. In the left sidebar, go to **Administration → Service Accounts**.
2. Select **Create**.
3. Enter a **Name** - lowercase letters, numbers, and hyphens, 1–63 characters, not starting or ending with a hyphen (for example, `github-actions`). The name cannot be changed later.
4. Optionally add a **Display Name** and **Description**.
5. Select **Create**.

The new account gets an email-style identity such as `github-actions@serviceaccount.local`, shown on its **Details** tab. Assign it a role binding so its keys can do something - see [Token security best practices](/platform/tokens/best-practices#least-privilege).

<Info>
  Create one service account per use case - one for CI, one for Airflow, one for monitoring - so you can revoke or rotate one without disturbing the others.
</Info>

### Add an API key

1. Open the service account and go to the **API Keys** tab.
2. Select **New Key**.
3. Enter a **Key Name** (for example, `prod-deploy-2026`), 1–128 characters.
4. Set **Key Expiry** in days (default 90, maximum 3650), or tick **Never expires**.
5. Select **Create Key**, then copy the key immediately.

Like PATs, an API key is shown only once. Store it in a secrets manager before closing the dialog. If you lose it, create a new key and revoke the old one.

### Use a service account API key

For service accounts the common convention is the `X-API-Key` header (both headers work, just as with PATs).

GitHub Actions - store the key as an Actions secret, never in the workflow file:

```yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
- name: Run e6data query
  env:
    E6DATA_API_KEY: ${{ secrets.E6DATA_SERVICE_ACCOUNT_KEY }}
  run: |
    curl -s -H "X-API-Key: $E6DATA_API_KEY" \
      https://<workspace>.e6.run/api/v1/catalogs
```

Python (Airflow tasks, services, scripts):

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import os
import requests

api_key = os.environ["E6DATA_SERVICE_ACCOUNT_KEY"]
resp = requests.get(
    "https://<workspace>.e6.run/api/v1/catalogs",
    headers={"X-API-Key": api_key},
)
resp.raise_for_status()
print(resp.json())
```

### List and revoke API keys

The **API Keys** tab lists every key on the account (name, prefix, created, expiry). Select **Revoke** next to a key and confirm - it stops working immediately. Deleting the service account revokes all of its keys at once.

## Token expiry

Expiry is optional for both PATs and API keys. In the Console you enter it as a number of days; it is stored as an RFC 3339 timestamp (for example, `2026-12-31T23:59:59Z`) and checked on every request.

An expired token returns `401 Unauthorized` (`invalid or expired API token`). Expired tokens cannot be extended - create a replacement and revoke the old one.

| Use case | Suggested expiry |
| - | - |
| BI tool connection (Tableau, Power BI) | 90 days - rotate quarterly |
| CI/CD pipeline key | 365 days - rotate annually or on team changes |
| Short-lived script or investigation | Hours to days - match the task |
| No expiry | Only with a rotation process already in place |

## Rotating a token

Rotate before expiry, and immediately if a token might have been exposed. Use **create-before-delete** so there is no gap where nothing works:

1. **Create** a new token (or API key).
2. **Update** your application or secrets manager with the new value.
3. **Verify** the new token authenticates correctly.
4. **Revoke** the old token.

## Troubleshooting

| Symptom | Cause | Fix |
| - | - | - |
| `401` - `invalid or expired API token` | The token expired, was revoked, or was copied incorrectly | Check the expiry; re-copy the full value; if needed create a new token and revoke the old one |
| `401` - `invalid API token format` | The value isn't a well-formed e6data token | Re-copy the whole token, including the `e6pat_` / `e6sa_` prefix |
| `412` - `AccessToken not configured for this workspace` | The token system hasn't been initialized for this workspace yet | A workspace Admin needs to configure it once (`POST /api/v1/accesstokens/configure`) before tokens can be created |
| `403 Forbidden` | The token is valid, but its identity lacks the required permission | Ask an Admin to add or adjust the role binding for your user or service account |
| Works in `curl` but not in my BI tool | The tool sends credentials as HTTP Basic auth, which the token middleware does not accept | Use the e6data JDBC/ODBC driver (email = username, token = password), or configure the tool to send an `X-API-Key` header |

## Frequently asked questions

**I lost a token before saving it - can I get it back?** No. The full value is shown only once. Create a new token, update your app with it, then revoke the old one by UUID if you still have it.

**Can I use my PAT for a CI/CD pipeline?** You can, but don't. A PAT is tied to your personal identity and will stop working if you change roles or leave - breaking the pipeline. Use a service account instead.

**What happens to my tokens if my workspace access is removed?** They still authenticate (the token is valid), but every call returns `403 Forbidden` because you no longer have a role binding. An Admin re-granting you a role restores access - you don't need new tokens.

**Why does e6data accept two different auth headers?** The middleware checks `X-API-Key` first, then `Authorization: Bearer`. Both work for both token types; the per-type conventions above are just the common choice.

## See also

* [Access tokens](/platform/tokens/pat-and-service-account-keys) - the canonical token-types table.
* [Token security best practices](/platform/tokens/best-practices) - storage, least privilege, revocation, and audit.
* [Roles and permissions](/platform/identity/roles-and-permissions) - the role bindings a token inherits.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.