Pair once. Resume for seven days.
Local pairing, browser trust, expiry and logout, with the exact HTTP contract.
On this page
Open the local Studio app at http://127.0.0.1:5188/ and enter the current
pairing code. Remember this browser for 7 days is selected by default.
After pairing, reloads, new tabs and reopening that browser can resume the session.
Use Log out to revoke this browser's saved access.
npm run pairing-codeRun the command in the Voice Studio workspace if the startup code has scrolled out of the terminal. It prints only the installation's current pairing code. It does not print the API bearer token.
What is remembered#
The browser receives an opaque, HttpOnly, SameSite=Strict, host-only cookie
restricted to /api/session. The local backend stores only the credential's hash,
its exact origin and its creation and expiry timestamps in the private
trusted-browsers.json file. This registry is outside the reviewed repository.
The bearer token used for ordinary API requests remains in browser memory.
The cookie by itself cannot authorize project API operations.
The lifetime is seven days from pairing. Reloading does not extend that deadline. The saved trust survives a backend restart; resume obtains a valid in-memory bearer again. The loopback HTTP cookie is not marked Secure because this local installation serves HTTP. This is a local app session design, not a hosted login service.
Address and browser scope#
Keep using the same browser profile and app address. localhost and 127.0.0.1
are distinct hosts; the port is part of the exact origin binding too. A different
profile, private browsing session, cleared site data or expired credential needs
pairing again. Leaving the checkbox unchecked creates a temporary in-memory
session: a page reload requires the code again.
Move the application directory#
Set VOICE_STUDIO_SESSION_ROOT in the host's startup environment to keep an
existing private session directory when VOICE_STUDIO_HOME changes. Read its
current location from .voice-studio/session-location.json in the old application
directory. Use the directory containing session.json, not the file itself.
The override must be an absolute local directory outside the application repository. Relative paths, filesystem roots, network/device paths on Windows, symlinks and junctions are rejected. Set it in a private launcher or service configuration; repository configuration and HTTP requests cannot select it. Without the variable, Studio keeps deriving its default private directory from the application path under the user's local application-data directory.
Stop the previous Studio process before starting the moved application with the
same private directory. The existing directory permissions and exclusive
instance lock still apply. Keep the directory and app origin unchanged: the
browser cookie name includes the private directory's identity. Copying
trusted-browsers.json into another directory does not preserve that identity.
A resumed browser keeps its original expiry and receives a new in-memory
bearer. Startup writes a new session-location.json pointer in the new
application directory.
Move the separate project registry, .voice-studio/projects.json, while Studio
is stopped. Preserve project IDs and update the roots of moved source projects
before the first start. Their .voice-lint/ directories contain the saved
reviews, tasks and proposals and must stay with those sources. External source
projects keep their current paths. Private check profiles in the retained
session directory's checks.json use absolute projectPath values; update only
the paths of projects that moved before restarting.
HTTP contract#
| Request | Input and outcome |
|---|---|
POST /api/session/pair |
{ code, remember }; returns { token, remembered, expiresAt } and sets browser trust when requested |
POST /api/session/resume |
Saved session cookie; returns a valid bearer and the original expiry, or HTTP 200 { paired: false } for absent/expired/revoked trust |
POST /api/session/logout |
Revokes this browser's credential and associated active bearer; expires its cookie |
Resume, logout and pairing with remember: true require the exact local
Origin and X-Voice-Studio-Session: 1. Temporary CLI pairing with
remember: false also works without those browser headers. A page on an unrelated origin cannot resume or revoke
the session just by sending the cookie. Normal project APIs require a bearer.
The existing private CLI installation token continues to work for local tools;
it is never stored in a browser cookie or published in evidence.
The UI resumes when it starts. After a token becomes invalid, a read may resume and retry once. Writes and model starts are never automatically replayed. A definitive authentication failure returns the UI to pairing. Session-generation guards prevent a late response from an older request from clearing a newer login.
Verification and scope#
The offline backend suite covers pairing, cookie restrictions, origin binding, absolute expiry, restart persistence, revocation and a changed application home with the same explicit private session directory. UI state tests exercise resume, unauthorized-response handling and late-response races.
npm run test:session
npm run test:session-ui
npm run test:browser-sessionThe real Chrome scenario uses an isolated browser profile and verifies a full close/reopen, reload, a new tab, logout, origin rejection and temporary mode. It does not write project source, create a proposal or start a model. This proves the tested local Chrome workflow; it is not cross-browser or hosted-service qualification.
Git and source reference
Source for this page: docs/browser-session.md. Content hash and Git revision: Build record.