← All documentation

How a saved login is stored

The highest-sensitivity thing Demofy ever holds, and the four mechanisms that hold it: sealed in the web process, never presigned, never plaintext in storage, destroyed after capture.

A saved session is a set of cookies that identifies you to your own product. It is the most sensitive thing Demofy ever holds, and this page states exactly how it is held so you can decide whether to hand one over.

If you have not met the feature yet: Recording behind a login is what it is for.

Four mechanisms, in the order they apply

1. It is encrypted before it leaves the process that received it

A session blob arrives in the request body of the web process and is sealed there — authenticated encryption under a key that lives in the deployment's environment, never in the database and never in the object store. Only the sealed envelope is written down.

The key ring is versioned, so rotating it is prepending a new key: existing sessions keep opening under the old one and are re-sealed under the new one the next time they are written back.

2. There is no upload URL for it, ever

Every other file you give Demofy — a stinger, a soundtrack, a logo, an imported video — goes straight from your browser to storage on a signed URL, because those files are large and that is what signed URLs are for.

A session deliberately does not. That path would put a plaintext credential in an object store and hand a browser a write capability aimed at it. A browser session is small, so it rides the request body, is validated against a schema at the door, and is encrypted before a byte reaches storage.

The same rule governs the hosted login browser: that service holds no durable credential at all — no encryption key, no database, no storage — and hands the plaintext session to the web process over one signed internal call, which then runs the ordinary save.

3. Plaintext is never presigned and never logged

A saved session has no readable URL. It is not in the list of a job's artifacts, it is never signed for reading, and nothing in the product will hand it back to a browser — including yours. There is no "download my session" and there is not going to be one.

A session that you start and never save leaves nothing anywhere. The browser dies and the memory goes with it.

4. A one-shot session is destroyed, versioned deletes and all

There are two shapes here and the difference is the whole design.

A one-shot session, attached to a single job, is shredded right after capture — and on every failure exit, and on expiry. Shredding means a version-aware hard delete: every version and every delete marker of that exact key is destroyed, data versions before markers, so a failed sweep fails toward hidden rather than toward resurrected.

That distinction was once a real gap. Object storage keeps versions by default, so an ordinary delete writes a marker and leaves the credential as a hidden prior version — which made the privacy claim false at the storage layer until it was found and the backlog destroyed.

A saved connection must survive capture — reusing it is the entire feature — so it is deliberately not shredded. The two are kept apart by the type of the thing the worker is handed rather than by a conditional somebody could get wrong, and the test that matters asserts that discarding a connection touches storage not at all.

What else is true

  • A connection belongs to a person, not a workspace. Colleagues cannot list yours, pick yours or spend yours — re-shooting a demo that was recorded with a saved login is the author's alone.
  • It expires on its own. Unused for 30 days, it is deleted: object first, then the row. Using it refreshes the clock.
  • It stays fresh while you use it. Apps rotate cookies; the updated session is written back and re-sealed after a capture, so a connection in regular use stays signed in indefinitely.
  • It is deleted when you delete it, object before row, and "Delete everything" includes connections and reports how many it removed.
  • If the deployment has no encryption key configured, the feature refuses politely rather than storing anything unencrypted. A job that names a connection fails at pickup, and the save explains itself. Unset is a working configuration; unset and silent would be a defect.

What Demofy does with it during a job

It is opened in the worker, written to the browser profile for that one job, and the run proceeds signed in. Discovery and capture both use it, which is not incidental: two browsers presenting different identities to one site get served different pages, and a demo built on a page the capture never saw is a broken video.

Before the job starts, the login is checked — the signed-in leg is replayed and compared against where a logged-out visit landed when you saved it. Only an exact match on the recorded logged-out URL fails the job. Anything ambiguous passes, because the check may only turn a certain late failure into an early one.