Skip to content

API tokens

Mint one, scope it, and know when it expires.

A token is how your own agents and scripts reach your project.

Settings, then Agents. Choose a name, the scopes, and a lifetime.

The secret is shown once. Whoever asked has it, or they do not: there is no “show it again”, because a token a product can show twice is a token the product is keeping.

sls_c4NCj0te.<secret>

sls_ and then base64url. The prefix is a fixed 12 characters and is stored in clear, which does two things:

  • verification is one indexed read rather than a hash comparison against every row;
  • a token found in somebody’s logs can be traced to its row and revoked, without the log ever having held the secret.

The visible sls_ marker makes a leaked token greppable. A secret nobody can recognise in a paste is one nobody notices has leaked.

ScopePermits
docs:readRead pages, history, diffs. Run the linter. Call /v1.
docs:writeStage a create, update, move or delete.
docs:commitCommit on a branch, and open a pull request.

Mint the narrowest token that does the job.

A token carries both the workspace and the project. It reaches that project and no other, so there is no header to get wrong and no way to point a script at the wrong site by accident.

Every token has an end, and the maximum is 365 days.

There is no “never expires” option. A token with no end is a credential nobody revokes, and the reason nobody revokes them is that nothing ever reminds them to.

SHA-256 of the secret. The token itself is never stored.

Why SHA-256 and not a slow hash

Slow hashing exists because a password is low-entropy and guessable. A token is 32 random bytes, and guessing is not a threat anybody can mount.

The real threat is a stolen database, against which a fast hash of high-entropy input is exactly as unguessable — while a slow hash would mean every API request paying about 90 milliseconds to check a bearer.

Revoke on the same screen. It takes effect immediately.

Every token shows its prefix, its scopes, its expiry, and when it was last used. The last-used column is how you find the ones nobody needs.

Minting and revoking are both recorded in the audit log.

Danger

Never put a token in a file your repository tracks. Use an environment variable and reference it:

{ "headers": { "Authorization": "Bearer ${STALELESS_PROJECT_TOKEN}" } }

A literal token in a tracked configuration file reaches your repository on the next commit, and repository history is not a place you can delete a secret from.

For staleless check the token is read from STALELESS_TOKEN and there is no flag for it, because a runner echoes the command it runs and a CI log is kept for months.

  1. Revoke it. Do this first.
  2. Mint a replacement with the narrowest scope that works.
  3. Check the audit log for what the old token did.

A revoked token cannot be reactivated. There is nothing to recover, which is the point.