The handshake
The JWT rides in the URL fragment (#…), never a query param, so the token stays out of server logs — Papervine reads it client-side.
Why a redirect works
A top-level browser redirect doesn’t carry the SPA’sAuthorization header, but it does carry cookies, and the API authenticates from those:
| Session | Cookie | Authenticated on a redirect? |
|---|---|---|
| Legacy / token | pixwel_api_credentials | yes — read by the Http auth adapter |
| Clerk | __session | yes — Session::docs() verifies it with the Clerk key when there’s no Authorization header |
pixwel_host) so they can sign in.
The pieces
| Component | Path | Role |
|---|---|---|
| Minter | api/controllers/Session.php → docs() | GET /session/docs?redirect=… — authenticates from cookie, signs the JWT, and 302-redirects to the Papervine callback |
/{:controller}/{:action} dispatches /session/docs to Session::docs.
The token
Signed EdDSA (Ed25519) withfirebase/php-jwt. Claims:
| Claim | Value |
|---|---|
host | the docs domain (docs.pixwel.com); must match or Papervine rejects it |
exp | now + 5s — the handshake window only (Papervine requires ≤ 10s) |
expiresAt | now + 8h — the docs session length |
groups | ["admin"] or ["user"], from $user->is(GroupsModel::ADMIN) |
email | the user’s email, for personalization |
redirect path is validated (must be site-relative) to prevent an open redirect.
Configuration
Point Papervine’s JWT login URL at the minter, and set two environment variables (both issued from the Papervine dashboard):| Setting | Value |
|---|---|
| Papervine login URL | https://platform.pixwel.com/api/session/docs |
papervine_jwt_private_key | base64 Ed25519 private key (also accepts a PKCS#8 PEM) |
papervine_docs_host | the docs domain, e.g. docs.pixwel.com |
503 docs_auth_unconfigured.
Role-based pages
Thegroups claim drives per-page visibility. A page restricted to a group uses frontmatter:
groups are visible to anyone past the docs login. The entire Engineering tab is tagged groups: ["admin"].
Setup checklist
Generate the keypair
In the Papervine dashboard, generate the EdDSA keypair and set the JWT login URL to
https://platform.pixwel.com/api/session/docs. Store the private key as papervine_jwt_private_key.Serve on a subdomain
Host the docs at
docs.pixwel.com — auth isn’t supported on a path basepath like pixwel.com/docs.