Releap Proof: durable UI Review authentication

Visual UI Review drives a headless browser to navigate and screenshot your app. To reach pages behind a login, it needs a way to authenticate. The Proof Endpoint credential is the recommended option for production apps that authenticate with a session cookie (SvelteKit, Rails, Django, Laravel, most SSR web apps) — especially when login is Magic Link, SSO, or anything a form-fill can't drive.

Why a proof endpoint instead of an API key or a pasted cookie

A session-cookie app authenticates the browser, not API callers — so an injected API-key header is invisible to it, and discovery only ever finds your public/pre-login routes. You could paste a session cookie (the Session Token credential), but it expires and must be re-pasted, and the stored value is itself a standing, long-lived session.

A proof endpoint flips that around. You store one long-lived shared secret; before every run Releap calls your endpoint with it, and your endpoint returns a fresh, short-lived, read-only session. The durable thing is a minting key, not a usable session:

  • One-time setup — configure the secret once; no periodic re-pasting.
  • Limited-time access — each run gets a new session you scope to a short TTL (we recommend ~15 minutes).
  • Read-only — mint a session that can view but not mutate, so a crawl can never change your data.
  • Smaller blast radius than an API key — if the stored secret leaks it only mints bounded read-only sessions (and you rotate it); if a minted session leaks it self-expires and can't write.

The contract

Host an HTTPS endpoint anywhere in your app. Before each run Releap sends:

POST https://yourapp.com/releap-proof/session
Content-Type: application/json

{
  "releap_shared_secret": "<the secret you configured in Releap>",
  "workspace_id": "<your Releap workspace id>",
  "service_id": "<the UI-Review service id>",
  "requested_scopes": ["read"]
}

Verify the secret, then return 200 with:

{
  "token": "<a session value — e.g. a fresh app_session cookie>",
  "expires_in": 900
}

Releap injects token exactly as you configure the credential: as a cookie (set Token type = Cookie and Cookie name to your session cookie, e.g. app_session) or as a bearer header. Return a non-200 to fail the run loudly (Releap marks it proof_endpoint_auth_failed rather than silently crawling logged-out).

Reference handler

Language-neutral — the three steps are the same everywhere. Mint the session with your own auth system; the key is that it's fresh, short-lived, and read-only.

handle POST /releap-proof/session:
  body = parse_json(request)

  # 1. Authenticate with a CONSTANT-TIME compare. If your secret env is
  #    unset, treat the endpoint as disabled (503) so it's never open.
  if not constant_time_equals(body.releap_shared_secret, env.RELEAP_PROOF_SECRET):
      return 401

  # 2. Only ever mint read scope from here.
  if body.requested_scopes != ["read"]:
      return 403

  # 3. Mint a fresh, short-TTL, READ-ONLY session for body.workspace_id
  #    using your own session system. Give it a viewer/read-only role (or a
  #    service identity with no write permissions). 15 minutes is plenty.
  session = create_session(
      workspace = body.workspace_id,
      role      = "viewer",        # cannot mutate
      ttl       = 15 * 60,
  )

  return 200, { "token": session.cookie_value, "expires_in": 900 }

Set it up in Releap

1. Host the endpoint

Deploy the handler above. Store its secret as a high-entropy random value in your environment / secret manager — never in code.

2. Add the credential

In Releap go to Plan → Services → + Add credential and choose Proof Endpoint (Automated). Enter your Endpoint URL, set Token type to Cookie and Cookie name to your session cookie (e.g. app_session), and paste the same shared secret you configured on your endpoint.

3. Point your service at it

On the UI-Review service, set the Base URL to an in-app route (so discovery starts inside the authenticated shell), select the Proof Endpoint credential, then run Auto-discover and Verify routes — each route should show as reachable rather than “needs login.”

4. Allowlist (optional)

If your endpoint restricts inbound IPs, allowlist Releap's worker ranges — see Releap Proof IPs.

Rotating & revoking

To revoke access, change the secret on your endpoint (and update the credential in Releap, or remove it). Because every run mints a fresh session, there's no long-lived token to hunt down — in-flight sessions lapse at their TTL.