Skip to content

One sign-in, and a host app can hand the panel a session - #73

Open
DavertMik wants to merge 5 commits into
mainfrom
feat/single-auth
Open

One sign-in, and a host app can hand the panel a session#73
DavertMik wants to merge 5 commits into
mainfrom
feat/single-auth

Conversation

@DavertMik

Copy link
Copy Markdown

Replaces #72, which described an earlier version of this contract.

Two things, and the second is why the first got simpler.

One credential

Authorizing at /app-auth hands back a session that opens the web JSON:API and can read any project's own v2 key. So the panel needs one credential rather than two kinds of them: it mints per-project keys as it goes, and the tester never looks a key up.

Settings now leads with Open Testomat.io & authorize and takes the token that comes back. A General token still works — a stored credential starting with eyJ is adopted as a session, anything else goes onto v2 directly and still exchanges at /api/login. Nobody's saved token stops working, and that branch is deletable the day you want the old path gone.

Minted keys live in memory, one per project, cleared when the instance or the credential changes. PRIVACY.md says so.

A host app can sign the panel in

A desktop app that launches Chrome with this extension loaded drops handoff.json beside the manifest and opens the panel, so the tester never pastes anything to run the test the app just sent them to:

{
  "app": "Testeiya",
  "baseUrl": "https://app.testomat.io",
  "projectId": "my-project",
  "jwt": "eyJ…",
  "runUrl": "https://app.testomat.io/projects/my-project/runs/abcd1234",
  "at": 1756160000000
}

jwt is what the offer is made of. projectToken may ride along and saves the first key read, nothing more. runUrl is optional. at is milliseconds and has to grow on every push.

A file rather than a command line: --load-extension argv is readable by every process on the machine, and these are credentials. A panel already open takes a new push through window.TestomatHandoff.apply(), which answers {ok, projectId, run}; a build without that global predates the contract.

The session is never stored — it is re-read from the file on every panel load, which is why the file stays until the host that wrote it deletes it. Disconnect can't delete a file it doesn't own, so it marks that at answered and a newer push wins.

An offer overlays an ordinary sign-in rather than replacing it: a tester who had already connected keeps their credential and their preferences, and because any session reaches every project, the project switcher stays open. It closes in one case — the host closed its browser and the tester never signed in themselves, leaving a stored project token that opens that one project.

Also here

openRunFromUrl now reports whether it actually landed the panel on a view. A run that 404s used to leave the panel showing nothing at all, reachable today through "Run in Extension".

Checked

Against a real instance, watching the Authorization header on live requests: a JWT-only sign-in minting a tstmt_ key; a project switch minting the second project's key; a handoff with a project token using it on its own project and minting elsewhere; a General token unchanged. Plus a jwt-only handoff, cold boot, a live poke switching runs in place, decline-then-newer-push, and the editor and viewer clean under a session-only sign-in.

Untested: the branch for a role whose project returns no API key, and the expired-session message. Both are written; neither had an account to prove it with.

With no host involved the panel logs one ERR_FILE_NOT_FOUND for handoff.json at boot. That is the check for the file, not a fault.

🤖 Generated with Claude Code

A desktop app that launches Chrome with this extension loaded drops
handoff.json beside the manifest: a project token for v2, a web session
for the JSON:API, and optionally the run to open. The tester pastes
nothing.

A file, not argv — --load-extension command lines are readable by every
process on the machine. Only the project token is stored; the session
token stays in memory and is re-read, like the one /api/login returns.
The project is pinned, since one project's token was handed over.
Disconnect cannot delete a file it does not own, so it marks that push
answered and a newer one wins.

Also: opening a run from a URL now reports whether it landed anywhere.
A run that 404s used to leave the panel showing nothing at all.
A panel the host has just opened consumes the offer during its own boot,
so the poke that follows found the run already opened and reported none.
The host asked whether its run is up, so answer that.
Adopting a handoff used to delete the General token saved for that host,
so closing the host's browser left the panel with nothing and the tester
re-pasting a token they had already given us.

Both credentials are kept side by side instead. The project token is
tagged with the project it was issued for and used only there, so a
switch elsewhere falls back to the account token — which also means the
switcher only has to be pinned for a tester who has no token of their
own. The host's name is stored with the connection, because the card has
to name whose session ended after the file it came from is gone.
Authorizing at /app-auth hands back a session that both opens the web
JSON:API and can read any project's own v2 key. So the panel needs one
credential, not two kinds of them: it mints per-project keys as it goes
and the tester never looks a key up.

The paste box takes either kind. A stored session is adopted the same way
a handed one is, adopt-once so an expired token degrades instead of
looping; a General token still goes straight onto v2 and still exchanges
at /api/login, so nobody's saved token stops working.

Because a session reaches every project, the handoff's projectToken drops
to an optimisation — one round trip saved — and the project switcher no
longer has to be pinned for a handed-off connection.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants