API Tokens
Reference for varsafe API tokens — creation, project and environment scoping, expiration, rotation, revocation, and security properties.
API tokens give CI/CD pipelines, automation scripts, and service accounts programmatic access to secrets without an interactive login. This page is the token reference; for step-by-step pipeline setup, see the CI/CD guide.
Overview
| Property | User Session | API Token |
|---|---|---|
| Authentication | Browser-based login | Bearer token in environment |
| Scope | All teams you belong to | Exactly one team (optionally narrowed) |
| Expiration | 7 days, rolling renewal | Fixed, set at creation (plan-capped) |
| Audit trail | Shows user email | Shows the token as actor |
| Best for | Interactive CLI use | Programmatic access |

Token Properties
- Team-scoped — a token belongs to exactly one team and can never access another team’s data
- Name — 1–100 characters, for identification (e.g., “GitHub Actions - Production Deploy”)
- Access level —
write(the default) orread. A read-only token can read secrets but is refused on every write. See Access level - Project scoping (optional) — restrict the token to specific projects; unscoped tokens can access all of the team’s projects
- Environment scoping (optional) — restrict the token to specific environments by slug (e.g., only
staging); unscoped tokens can access all environments
- Expiration (always set) — every token expires. If you do not choose a lifetime, the plan maximum is applied:
| Plan | Maximum token lifetime |
|---|---|
| Developer | 90 days |
| Team | 365 days |
- Format — tokens start with the
vs_at_prefix; only a salted hash is stored server-side - Last-used tracking — each authenticated request records the timestamp, IP address, and user agent, visible in the dashboard
Creating a Token
Only owners and admins can create and manage tokens (roles reference).
- Go to your team settings in the dashboard
- Navigate to API Tokens
- Click Create API Token
- Enter a descriptive name
- Choose Read-only under Access if the token never needs to write
- Optionally scope the token to specific projects and environments
- Optionally set a shorter expiration than the plan maximum
- Click Create and copy the token immediately
Access level
Every token carries an action ceiling, evaluated separately from its project and environment scoping.
| Level | Effect |
|---|---|
write |
Read secrets, and create, update, rotate, roll back or delete them, within the token’s scope. The default when no level is requested |
read |
Read secrets within the token’s scope. Creating, updating, rotating, rolling back and deleting are all refused |
Choose read-only for anything that only consumes secrets — a CI job that injects configuration at deploy time, a service that reads config at boot, a script that inventories keys across projects.
The level also does not reach past the API. It stops writes to varsafe; it does not stop the machine holding the token from writing what it read to a local file — varsafe export --plain works with a read-only token. A token may also always revoke itself (DELETE /me/token), which is deliberate: a compromised credential should be able to kill itself without an admin.
Set it in the dashboard when creating the token. Driving it over the API instead means
POST /teams/{teamId}/api-tokens with an accessLevel field:
{ "name": "ci-inject", "accessLevel": "read" }
Omitting the field yields a write token.
The request body is strict: a misspelled key such as accessLevell is rejected with 400
rather than ignored. That matters more here than elsewhere — dropping it would answer a
request for a narrower credential with a full read-and-write one.
To confirm what a token you already hold can do, ask the API with the token itself:
curl -sH "Authorization: Bearer $VARSAFE_TOKEN" https://api.varsafe.dev/me/verify
The response carries accessLevel for token principals.
Narrowing an existing token
A token can be changed to read-only after the fact — no rotation window, and the token
already in circulation keeps working with the narrower ceiling. Do it from the token’s row
in the dashboard, or with PATCH /teams/{teamId}/api-tokens/{tokenId} and
{"accessLevel":"read"} from an admin session.
The change applies to every request authorized after it commits. A write that already passed its authorization check runs to completion, so narrowing is not a way to abort work in flight — revoke the token if you need to stop it now.
This ratchets one way only: widening read back to write is refused, so create a new
token instead.
Tokens minted for headless CLI logins are the exception — their access level cannot be
changed at all (renaming still works). The level is derived from the CLI’s granted scopes
when the device is exchanged, so the next login on that machine would restore write if the
new grant includes secrets:write, silently undoing the narrowing. Re-issue those with
narrower scopes rather than editing them.
MCP scopes
A token can also authenticate an AI agent against the hosted MCP endpoint — useful on a machine with no browser, or when the agent should act as a different account than your CLI. See the MCP guide for client configuration.
This is opt-in per token. A token with no MCP scopes is refused by the MCP endpoint, so existing tokens gain nothing until you grant them scopes explicitly.
What you can grant is bounded twice over:
- By the token’s access level. A read-only token cannot hold
secrets:write. Narrowing a token to read-only later removes that scope in the same change, so the ceiling and the agent surface can never disagree. - By your own role. You cannot grant a token more MCP authority than you hold yourself — the same role limits that apply on the consent screen.
Like the access level, the scope set ratchets one way: scopes can be removed, never added. Removing all of them switches the agent surface off while leaving the token working for the HTTP API.
Actions taken through a token are audited as the token, not as the person who created it. The creator’s membership still governs it — if they leave the team or are deactivated, the token stops working everywhere, MCP included.
Using a Token
Set the token in the environment; the CLI picks it up automatically. VARSAFE_API_TOKEN is the primary variable, VARSAFE_TOKEN is an accepted alias:
export VARSAFE_API_TOKEN=vs_at_vsafe_example
varsafe run -p my-api -e production -- ./deploy.sh
For a persisted login (saved to the encrypted credential store), use one of the safe input paths:
# Secure prompt — masked input, nothing in shell history
varsafe login -T
# Stdin pipe — from a CI secret or secure store
echo "$VARSAFE_TOKEN" | varsafe login -t -
# Environment variable
VARSAFE_TOKEN=vs_at_vsafe_example varsafe login
See CLI Authentication for all input methods, and the CI/CD guide for GitHub Actions, GitLab CI, and other pipeline recipes.
Rotation
Rotation revokes the old token and issues a new one with the same name and scoping in a single step:
- Go to team settings → API Tokens
- Click Rotate next to the token
- Copy the new token
- Update your CI/CD secrets
Revocation
If a token is compromised or no longer needed:
- Go to team settings → API Tokens
- Click Revoke next to the token
- Confirm revocation
Revocation is immediate and permanent.
Security Properties
- Hashed at rest — varsafe stores a salted hash, never the token value
- Shown once — the plaintext value exists only in the creation response
- Always expiring — no forever-tokens; the plan cap bounds the damage window of a leak
- Scoping narrows blast radius — a token scoped to one project and one environment can leak nothing else
- Audited — creation, update, rotation, revocation, and deletion each produce an audit event (
api_token.*), and every secret access by a token is logged with its identity
Best Practices
- One token per purpose — separate tokens for separate pipelines
- Scope tightly — restrict to the project and environment the pipeline actually needs
- Short lifetimes — pick the shortest expiration your rotation cadence supports
- Immediate revocation — revoke tokens the moment they are no longer needed
- Secure storage — keep tokens in your CI/CD secrets manager, never in code
Troubleshooting
Invalid token
- Verify the token is correct (no extra spaces or line breaks)
- Check whether the token was revoked or has expired (team settings → API Tokens)
- Ensure
VARSAFE_API_TOKEN(orVARSAFE_TOKEN) is set in the environment the command runs in - Try
varsafe login -Tto paste the token with masked input
Token not authorized
- The token may belong to a different team than the project you are targeting
- The token may be scoped to other projects or environments — check its scoping in the dashboard
Rate limited
Token requests share the standard authenticated API rate limits (per-second, per-10-second, and per-minute windows). If a pipeline is throttled, reduce request frequency or batch work; for sustained higher limits, contact support.
Multiple Environments
Option 1: One token, environment scoping open, select at run time
varsafe run -p my-api -e staging -- ./deploy.sh
varsafe run -p my-api -e production -- ./deploy.sh
Option 2: Separate tokens per environment
Create one token scoped to staging and another scoped to production. Each pipeline can only touch its own environment, and the audit trail separates them cleanly.
Security Checklist
- Tokens stored in CI/CD secrets, not in code
- Each pipeline has its own token
- Tokens scoped to the narrowest project/environment set that works
- Unused tokens revoked
- Expirations set to the shortest workable lifetime
- Audit logs reviewed regularly