dropto.run docs
Guides

Authentication

A browser authenticates with a session cookie. Everything else — the CLI, the MCP server, CI — uses a personal access token.

Getting one

On your own machine, let the CLI do it:

TerminalCode
drop2run login # opens a browser, listens on 127.0.0.1 drop2run login --device # for SSH, containers, WSL — approve a code at app.dropto.run/device

Either way the token is minted, named after the machine, and written to ~/.config/drop2run/config.json with mode 0600. You never see the string, which is the point: a credential you never copy is one you cannot paste somewhere it should not be. See CLI.

In a chat, let the MCP server do it: its login tool runs the same browser sign-in and writes the same file, and login_code is the same code flow as --device. Nothing is installed and no token is pasted — ask for a publish and the sign-in happens on the way. See MCP server.

By hand, for CI — where nothing can open a browser or approve anything:

  1. Sign in at dropto.run
  2. Open Account → Access tokens
  3. Name it after where it will live: ci, deploy-runner

That one is shown once. The server stores a SHA-256 hash and the first twelve characters, so nothing — not this site, not support, not the database — can show it again. Lose it and the answer is to revoke it and make another.

Both routes produce the same kind of token with the same powers. The difference is only who typed it.

Using one

TerminalCode
curl -H "Authorization: Bearer d2r_..." https://dropto.run/api/sites

Tokens look like d2r_ followed by 43 base62 characters. The prefix is fixed so a secret scanner can recognise one in a leaked file, and the body avoids -, +, / and = so nothing that pastes it — a shell, a URL, a YAML file — breaks it in half.

The CLI and the MCP server read a token from DROP2RUN_TOKEN, or from ~/.config/drop2run/config.json:

JSONCode
{ "token": "d2r_..." }

The environment wins. Both tools use the same file and the same precedence, so signing in once covers both.

What a token cannot do

It cannot create or revoke tokens. Both need a browser session — including through the CLI and the MCP server: login, login --device and the login_code tool all end at a page you approve while signed in, which is exactly what makes them allowed to produce one. A model calling login cannot mint itself anything; it can only ask you to approve a sign-in.

This is the one restriction worth understanding rather than working around. Without it, a leaked token is not a leaked credential — it is a permanent one: whoever takes it mints a second, and revoking the first achieves nothing, because the replacement is a token you never made and will not recognise in your list. gh and vercel draw the same line.

It cannot reach the admin console. /api/admin requires a cookie session and an internal account.

Tokens and two-factor sign-in

A token is not a sign-in, so it never asks for a code. Turning two-factor on does not end the tokens you already have — revoke them from Account → Access tokens if that is what you wanted.

Getting one does go through a sign-in. login, login --device and login_code all end at a page you approve in the browser, and signing in there asks for your code like any other sign-in. If a team you belong to requires two-factor, approving is refused until you turn it on:

JSONCode
{ "type": "two_factor_required", "title": "Two-factor required", "status": 403 }

When an owner starts requiring it, members' existing tokens keep working — a CI job does not break at the moment the rule changes. The confirmation the owner sees before turning it on says how many tokens are held by members who do not have two-factor yet.

When one stops working

A rejected token gets 401 with invalid_token, not 403:

JSONCode
{ "type": "invalid_token", "title": "Token not accepted", "status": 401 }

The difference matters to a script. 401 means the credential is the problem — revoked, expired, or the account can no longer publish. 403 means the credential is fine and the request is not allowed: the site belongs to somebody else, or the plan does not include what was asked for.

Which of those four applies is not reported. To whoever holds the token they are one answer — stop using it — and saying which would tell somebody holding a stolen one whether the account had noticed.

Knowing which tokens are still in use

Every authenticated request stamps last_used_at, at most once every five minutes. The account page shows it, and it is the only thing that tells a token still in use from one worth revoking.

That column is the whole compensation for tokens being long-lived. They do not expire on their own unless you give them an expiry, which is the trade: convenient for CI, and a leak lasts until somebody notices.

Last modified on