VCode home

Log in with the token

Agents: claude, codex, opencode · On: phone, desktop

Paste the server's AUTH_TOKEN into the sign-in card once per device. The server swaps it for a cookie that lasts 90 days, and the raw token is never sent again.

Why you would use it

Every installed machine sets a token, because the app runs agents with approvals bypassed. This is the one screen that stands between a browser and a shell on your machine.

How to use it

  1. Open the app. The sign-in card (#auth) covers the screen.

    The sign-in card as it opens: the logo and "locked" in the header, the title "Unlock VCode", the hint, the command row, an empty AUTH_TOKEN field with its Paste chip, and the Unlock button.

  2. On the machine running the server, read the token with the command the card shows: grep AUTH_TOKEN= ~/.config/v-code/env. The copy button at the end of that row (#auth-copy) copies the command. It prints only the AUTH_TOKEN= line, so the tunnel token in the same file stays off the screen. On the dev instance (install.sh --instance dev) the file is ~/.config/v-code/dev.env. The token is a 64-character hex string that install.sh minted with openssl rand -hex 32.

  3. Paste the token into the field (#auth-token), or copy it and tap the paste chip at the field's right end (#auth-paste), which reads the clipboard and fills the field. It is a password field with autocomplete, autocorrect, autocapitalise and spellcheck all off, and the placeholder reads AUTH_TOKEN. Spaces round the value, a leading AUTH_TOKEN= and quotes round the value are stripped, so the grep's line pastes as it prints.

  4. Tap Unlock (#auth-go), or press Enter in the field.

  5. The card closes and the app loads. The device stays logged in.

What you see

The card's header shows the VCode logo and an amber dot with locked (#auth-box). Once this browser has been signed in and learnt the box's name, it reads locked · <box>. The title reads Unlock VCode, with a hint line under it (#auth-hint) that changes with the situation:

Hint When
Paste the token from the machine running the server. The default in index.html
Session expired — unlock with the token. A request came back 401 or 403 while the app was open
Cannot reach the VCode server. Is it running? The server is unreachable and this browser has never talked to it
Offline, and no saved session. Connect once first. Unreachable, the remembered server wants a token, and you never logged in here

The error line (#auth-err) under the field shows that token was rejected — paste only the value after AUTH_TOKEN= for a wrong token (the server answered 401), and the field's edge turns red until you type in it again. The other messages leave the edge alone: too many attempts — wait a few minutes after the limiter trips, the server answered <status> — try again for any other failed answer (a 502 from the tunnel while the server restarts, say), server unreachable, or offline.

The card after a wrong token: the field has a red edge, holds masked characters, and the line under it reads "that token was rejected — paste only the value after AUTH_TOKEN=".

The card after eleven wrong tokens from the same address: the line reads "too many attempts — wait a few minutes".

The paste chip says why when it cannot fill the field: this browser does not let the page read the clipboard — paste by hand, clipboard read was refused — paste by hand or the clipboard is empty. A copy button that cannot write the clipboard says could not copy — select the command by hand.

The server's own replies, which you see with curl rather than in the UI:

Status Body
400 {"error":"token required"} — the POST had no token string
401 {"error":"wrong token"}
429 {"error":"too many auth attempts; wait a few minutes"}
401 {"error":"unauthorized"} — no credential on an API route
401 {"error":"session expired"} — a cookie that no longer verifies

Options and settings

Option Default What it changes
AUTH_TOKEN (unset — auth off) The token the card accepts. Unset means no card at all
VCODE_REQUIRE_AUTH 0 (1 in the unit) 1 refuses to boot without a token
Session lifetime 90 days SESSION_MAX_AGE_MS in lib/auth.js
Clock skew tolerated 5 minutes SESSION_SKEW_MS

Limits and known gaps