Tokens and access
The two kinds of turboEnv credential, exactly what each one can reach, and which to use where.
There are two kinds of credential and they are not interchangeable. Picking the wrong one is the most likely way to give something more access than it needs, so this page is worth five minutes.
The short version: a person logs in, a machine holds a token.
| Project token | Login credential | |
|---|---|---|
| Created by | The dashboard | turboenv login |
| Reaches | One environment, or one project | Every project the team owns |
| Can write | No, read-only | Yes, with turboenv push |
| Can delete a project | No | Yes, with turboenv delete |
-p / -e |
Optional | Required, unless turboenv.json sets them |
| Expires | Never on its own | 30 days without use |
| Works in CI | Yes | Refused on purpose |
| Revoke from | Tokens tab | CLI logins panel |
Project tokens
Created in the dashboard, on the Tokens tab of a project. Their scope is fixed when you make them and the caller cannot widen it afterwards.
An environment-scoped token is what a deployment should hold. It reads exactly one environment. Naming a different one is refused with a 403, and asking it about the project returns only its own environment — it cannot even enumerate the siblings it has no access to.
A project-scoped token, made by leaving the environment blank, reads any environment in that one project and has to say which it means on every call. It exists for tools that legitimately work across environments, which in practice means the MCP server diffing staging against production.
Neither kind can be pointed at a different project, and neither expires on its own. The token is shown to you once at creation. turboEnv stores only a SHA-256 hash of it and the first few characters, so we cannot show it to you again and a database leak yields nothing usable.
Both kinds are read-only. A token can read variables and cannot save a new
version; POST /v1/env refuses it. It also cannot delete a project;
DELETE /v1/projects/{slug} refuses it too. This is what makes a token safe to
put in a container image or an agent's configuration — the worst a leaked one
can do is expose the configuration it was scoped to, not change what your next
deployment reads and not destroy it.
Login credentials
turboenv login issues a credential scoped to your team rather than to a
project, so it reads every variable the team holds. That is a much wider grant
than a project token, and it is deliberate — a developer moving between the
services they work on should not have to mint a token for each one.
It is also the only credential that can change anything. turboenv push
needs one, so every saved version has a person's name against it rather than a
shared machine token's, and so does turboenv delete, which is the only way to
destroy a project from outside the dashboard.
Because it is wider, it is fenced in five ways:
- There is no implicit target.
-pand-eare required on every call, unless aturboenv.jsonsupplies them, because the credential does not point anywhere by itself. - Another team's project answers 404, not 403. A 403 would confirm the project exists, which turns the parameter into a way to discover what other teams have. So the answer is indistinguishable from a name that was never used.
- It expires after 30 days without use, renewed silently every time you use it. A laptop that stops being used stops being a way in, without interrupting anybody who is still working.
- It is refused in CI. See below.
- It is revocable from the CLI logins panel in the dashboard, which lists every machine signed in to your team with its hostname and when it was last used.
The credential is written to ~/.turboenv/credentials.json with mode 0600,
keyed by base URL so a self-hosted instance and the hosted one can both be
signed in without one replacing the other.
Why login is refused in CI
The CLI detects the environment variables that continuous integration systems set, and refuses to use a stored login credential when it finds them, even if the file is sitting right there.
A pipeline that works because somebody once ran turboenv login on the build
box is a pipeline that breaks the day that person leaves the company and their
credential is revoked. It also hands the build the ability to read every project
the team owns, when it needed one environment of one service.
Both problems disappear if CI holds an environment-scoped token, so the CLI
declines to let the shortcut exist. Set TURBOENV_TOKEN instead — see
Deploying and CI.
Which credential is used
Most explicit wins:
--tokenon the command lineTURBOENV_TOKENin the environment- A stored
turboenv logincredential
This ordering is why a project token in TURBOENV_TOKEN always beats whatever
you happen to be logged in as. Exporting one for a single command is a reliable
way to reproduce exactly what your deployment will see:
TURBOENV_TOKEN=tenv_live_... turboenv print
When somebody leaves
Removing a person from the team stops them signing in, but does not revoke credentials they created — tokens belong to the project, which is what keeps your deployments booting when their author changes jobs.
So, in order:
- Revoke their machine under CLI logins. It is the widest credential and the one that is on a laptop you no longer control.
- Revoke project tokens they created, in each project's Tokens tab.
- Rotate the underlying values for anything they could read and you cannot confirm is unused. Revoking access to turboEnv does not un-know a database password somebody has already seen.
That third step is the one people skip. A credential store makes distributing secrets safe; it cannot make a value that has been read by a departing employee secret again.