Password Protection
PageWeave can password-protect the surfaces a website is served on. Two independent gates, same mechanics:
| Surface | What it protects | Password set via |
|---|---|---|
| Any environment — including the default ("live") | Every request to the environment's hosts: the generated *.env.pageweave.site host and custom hostnames bound to it |
update_environment password / remove_password; create_environment optional password |
Release permalinks (*.r.pageweave.site) |
All *.r.* share links of the website, sitewide |
update_website release_password / remove_release_password |
The classic workflow is pre-launch privacy: protect the default environment (or a staging environment) while the site is being built, then remove the password to go live — the same pattern Shopify uses for new stores.
How the gate works
Every request to a protected surface requires a credential:
- Humans get a localized password page. A correct password issues an encrypted, host-only cookie (30 days,
HttpOnly,Secure,SameSite=Lax). The cookie binds a sub-second timestamp of the password's last change — rotating or removing the password invalidates every cookie already issued, immediately. - Automation sends the password as a bearer header:
Authorization: Bearer <password>. Header-only — no query-parameter tokens (they leak via logs and referrers).
Wrong credentials get 401 with the gate page. The gate POST is rate-limited to 10 attempts per minute per IP.
Each surface's password is independent: the environment password never unlocks release permalinks, and each environment has its own password.
Caching
Gated surfaces are never publicly cacheable. Every response — the 401, the gate form, and granted requests — carries Cache-Control: private, no-store. Conditional-GET (ETag/Last-Modified) still works for automation, but hash-marked immutable URLs (snippets, stylesheets) drop their year-long public cache on gated surfaces: a cache must never outlive a password rotation.
Storage security
Passwords are stored as bcrypt digests only. The plaintext is never stored — not in the database, not in workflow approval state, not in tool-call logs (tools pre-hash it into an opaque marker before anything is persisted). Agents should relay the password to the user in the same turn it is set; later calls cannot retrieve it.
There is no password reset by design: the owner can always remove or rotate the password via MCP (remove_password never asks for the old one).
Caveats
- While the default environment is protected, the showcase screenshot pipeline and search crawlers only see the gate page — protecting an already-indexed live site will de-index it until the password is removed. Intended for pre-launch privacy.
- Release permalinks served before a release-links password was set were public while they served; set the password before sharing links for gated content.
MCP usage
{"name": "update_environment", "arguments": {"website": "acme", "environment": "staging", "password": "correct horse battery staple"}}
Responses carry the state as flags: protected: true/false on environments (list_environments, get_website, create_environment, update_environment) and release_protected on the website (get_website, update_website). Approval cards show protection turning on/off — never the password itself.