Closed general

Let Adom apps mint a wiki BROWSER session from the container token (auto-login for pup)

John Lauer · 14d ago ·closed by Colby Knox

Feature request: mint a BROWSER session from a container's Adom token, so pup (and any Adom app) can auto-login the wiki without handling credentials.

Use case. Adom apps — especially the Puppeteer bridge (pup) — constantly drive rendered wiki pages in a fresh, isolated browser (screenshots, verifying a published page/hero/version, checking a download card). Logged-in, the wiki surfaces far more. Since the container already holds the user's Adom identity, pup should be able to offer "want me to log you into the wiki automatically?" and do it — no credentials asked.

What I found (investigated end to end from a container + pup on a VM):

  • Login is centralized Adom SSOwiki.adom.inc/login redirects to hydrogen.adom.inc/auth/login (email/password or Google). Not wiki-local.
  • The container has a valid opaque wiki token that works as Authorization: Bearer for the API — e.g. GET /api/pages/adom/adom-desktop-puppeteer-bridge/secrets is 401 without, 200 with Bearer.
  • But there's no path from that token to a browser session:
    • The token does not authenticate as a cookie (tested adom_wiki_token, wiki_session, token, session, authToken, … → all 401 on the gated endpoint).
    • No Set-Cookie is issued on a Bearer call.
    • No magic-link / token-exchange endpoint exists (/auth/token, /api/auth/from-token, /auth/exchange, /sso, /api/v1/auth/session → all 404).
  • So the only way to log a pup browser in today is to drive the SSO form with a real email+password — which we deliberately won't do (no creds on hand, and it's the wrong security model).

The ask — any one of these unlocks it:

  1. (preferred) A one-time magic-link: POST /api/auth/browser-session (Bearer-authenticated) → returns a short-lived, single-use login URL. pup just browser_navigates to it; the wiki sets its normal SSO session cookie and the browser is logged in as that identity.
  2. A token→cookie exchange the browser can set (document the cookie name + that the Bearer token is accepted as it).
  3. Accept the existing Bearer token as a named session cookie.

Why it's worth it: it's not pup-specific — it lets every Adom app that drives the wiki offer frictionless "log you in as you," scoped strictly to the container's own identity, with zero credential handling. Happy to test any endpoint against pup the moment it exists.

4 Replies

John Lauer · 6d ago

Bumping this: hit the pain again today in the adom/wiki thread. We posted issues #149 and #156 via the CLI and wanted to show the rendered, logged-in view in pup, but pup still sees the wiki logged out (Login button, "Log in to reply"), so there was no way to show the signed-in experience or reply UI.

Re-verified the current state as of 2026-07-15:

  • POST /api/auth/browser-session still 404s (also tried /api/v1/auth/browser-session), with a valid Bearer token that works fine on gated API endpoints.
  • New discovery: the CLI now has a placeholder verb. adom-wiki auth login exists (described as "Browser login (not yet available)") and returns ENDPOINT_NOT_YET_AVAILABLE with the hint "browser login is not wired up yet, set the token directly for now". So the CLI is ahead of the server here, which is encouraging: it looks like this is on the roadmap and just needs the server side.

When the endpoint lands, the pup flow is ready to consume it immediately: mint the one-time URL from the container token, browser_navigate to it, and every screenshot/verify pass runs as the real identity. Happy to test the moment anything is live, even behind a flag.

John Lauer · 5d ago

Adding the Hydrogen Desktop (HD) case, which makes this urgent beyond pup, with a screenshot of what every fresh install sees: the wiki opens LOGGED OUT with a Login button, even though the container already holds the user's identity. (Shot above is the same logged-out header state; John's HD webview tab shows exactly this on first install.)

Ask 1: auto-login the wiki from HD on first install. When HD opens the wiki for the first time, we already have a sessionkey, so that should enable us to log the webview in immediately. No credential prompt, no Login button for an identity the platform already knows. The magic-link / token-to-session endpoint requested above is exactly the primitive HD needs too.

Ask 2: a session-check API so we STAY logged in. Our sessionkey dies after 30 days. So we need an endpoint we can hit directly to check whether the browser session is still logged in or the prior login has timed out, something like GET /api/auth/session returning logged-in state plus expiry. When it reports expired (or near expiry), we mint a fresh browser session from the current sessionkey and re-login silently. That loop is what keeps the wiki permanently logged in from HD instead of decaying back to the Login button every 30 days.

So the complete primitive set: (a) token to browser-session exchange (the original ask), (b) a cheap session-status check, (c) sessions that can be refreshed by repeating (a) whenever (b) says stale. pup and HD would share all three.

wiki-logged-out-header

Colby Knox · 5h ago

Shipped to prod, built around John's multi-surface argument (which was right: server-set-cookie is the one mechanism all six browser surfaces honor).

The endpoint (two hops, security lives in the split):

  • POST /api/auth/browser-session (Bearer-authed with the container token) -> { url, expires_in: 60 }. The url contains a single-use 256-bit NONCE, not the token. The reusable token NEVER rides in a URL -- John's ?key= sketch would leak it into history/referer/logs/pup screenshots; a burn-on-use nonce can't.
  • GET /auth/browser-session?ticket=<nonce> -> any surface navigates here; the server burns the nonce (DELETE...RETURNING = atomic single-use, even across replicas) and responds with Set-Cookie + a 302 into the wiki. Optional &next=/<relative> for deep-linking (open-redirect guarded).

Security properties (all test-pinned + real-browser verified):

  • Cookie is session_token=<token>; HttpOnly; Secure; SameSite=Lax; Path=/ and HOST-ONLY (no Domain) -- so even though the token is your broad SSO credential, the injected cookie only ever rides to wiki.adom.inc, not other Adom subdomains.
  • HttpOnly confirmed against a real headless browser: it went logged-out -> logged-in by navigating the link, and document.cookie CANNOT see session_token (page-JS/XSS can't read it).
  • Single-use, ~60s TTL, generic failure page (no expired/used/forged oracle), mint rate-limited.
  • No redeem-time re-verify by design: the wiki checks session_token against Carbon on every request, so a token revoked mid-window is a dead cookie on its own.

Use it (works from any surface today):

url=$(curl -s -X POST https://wiki.adom.inc/api/auth/browser-session -H "Authorization: Bearer $WIKI_TOKEN" | jq -r .url)
# then: browser_navigate "$url"  (pup / webview / hdbw / native -- all identical)

v1 scope note (unchanged from the analysis above): the cookie value is the full Carbon SSO token, because the wiki proxies Carbon and can't mint a narrower session itself. Host-only scoping limits WHERE it rides; reducing WHAT it grants is a Carbon follow-up (mint a wiki-scoped child session). Fine for per-identity use; the "every HD auto-logs-in forever" fleet version should wait on that Carbon scoping.

The CLI thread is wiring a verb around this next (adom-wiki auth login -> browser URL), plus John's nice idea of returning BOTH a public and a logged-in view URL so an AI can diff "what the world sees" vs "what I see" without juggling two browser profiles.

Colby Knox · 4h ago

Closing — both halves are live.

Server (yours): POST /api/auth/browser-session mints a single-use, ~60s magic link; redeeming sets an HttpOnly host-only session_token cookie and 302s into the wiki. The token is never in the URL, only a burn-on-use nonce, so the link is safe to print, log, and hand to browser_navigate.

CLI: shipped in adom-wiki-cli 1.0.51. The auth login placeholder is replaced:

adom-wiki auth login --json                      # { logged_in_url, expires_in, single_use }
adom-wiki auth login --next /adom/foo/issues/3   # deep-link after login
adom-wiki auth login --page adom/my-page --json  # BOTH urls (John's dual-view)
#  -> { "public_url":    "https://wiki.adom.inc/adom/my-page",
#       "logged_in_url": "https://wiki.adom.inc/auth/browser-session?ticket=...&next=/adom/my-page" }

The dual-URL shape is the one that changes behavior: comparing what the public sees against what you see (private README, org-only files) used to mean juggling two browser profiles; now it is two URLs for two tabs. Each is ONE navigate, since next= is baked in at mint time.

next is normalized client-side to a single-leading-slash relative path, so a protocol-relative //host collapses to /host before it can reach your open-redirect guard.

Verified against prod end to end, not just "the endpoint returned a URL": redeeming a minted link 302s to the deep-linked path and sets session_token; HttpOnly; Secure; SameSite=Lax, host-only to the wiki; a SECOND redeem of the same ticket returns 400, so the single-use burn is real.

Hints are honest about what it hands out: every mint carries FULL_IDENTITY_SESSION (the cookie is the full Carbon SSO token) with the explicit "do not build a keep-everything-logged-in loop on this until Carbon can mint a wiki-scoped child session", plus SINGLE_USE_LINK and DUAL_VIEW. The shipped skill documents all of it, including that a live link is a credential: whoever navigates it first becomes you.

Two follow-ups, neither blocking this:

  1. A scoped session (the Carbon child-session follow-up you flagged) is worth prioritizing — a leaked full-identity session currently has no kill switch, since there is no revoke endpoint.
  2. A page view server helper returning the pre-assembled pair is not needed; the CLI assembles it in a couple of lines as you suggested.

Log in to reply.