Closed general

OAuth gateway session TTL is ~120s, but the client waits 10 min — leads to confusing 'Session Expired' when user clicks late

Drew Owens · 20d ago ·closed by John Lauer

The OAuth gateway session TTL (~120s) is much shorter than the client-side WS wait (600s / 10 min). The banner in adom-google auth reads "Waiting for the gateway… (up to 10 min)", but a fresh state token is dead within 2 minutes.

Repro (measured on 2026-06-30)

Start a fresh auth, then poll the gateway's /health every 15s. The pending counter tracks live sessions:

t+0s    pending=1   ← state registered, WS open
t+15s   pending=1
t+31s   pending=1
t+46s   pending=1
t+61s   pending=1
t+76s   pending=1
t+91s   pending=1
t+106s  pending=1
t+120s  pending=0   ← session dropped (gateway-side)

True gateway TTL is in (105, 120] seconds — almost certainly a hard 120s ceiling. The client-side WS stays open, silently oblivious, until its own 10-min timer fires. If the user clicks Allow after the ~120s window, Google POSTs the code to /callback, the gateway can't find the state → user sees "Session Expired. This authorization link has expired or was already used."

Where the numbers live

  • Client: _minimal_ws_roundtrip(ws_url, send_msgs, want_types, timeout=600) in adom-google (safe/full path). The "up to 10 min" string is at the cmd_auth print in the same file.
  • Gateway: oauth-9mycwxij7tif.adom.cloud — TTL not exposed via /health (only shows pending + uptime + brokerApps). Source repo not visible from user containers.

Ask

Either bump the gateway session TTL to match the client (600s = 10 min, so the banner is accurate), or shorten the client banner to reflect the real ~90-second comfortable window (build in some margin below the 120s gateway TTL for network + user reaction time).

If TTL asymmetry has to stay, at least log a clearer message client-side when a session-expired page comes through the gateway — e.g. include a hint like "gateway sessions currently expire in ~120s — re-run adom-google auth if you got the 'Session Expired' page" — so users don't wait out the full 10 minutes on a dead session.

Real-world impact

Bit us twice today in an agent-driven workflow (Adom Claude Code posting the URL to the user, user clicking it a couple minutes later). The failure mode is confusing because the CLI still says "Waiting for the gateway…" for another 8 minutes while the session is already dead. Losing that 8 minutes on a botched attempt is expensive when the user is on their phone or between meetings.

Happy to test a fix.

3 Replies

John Lauer · 5d ago

Fixed the client side in [email protected].

  • The auth banner no longer says "up to 10 min" — it now reads: "Approve WITHIN ~90 SECONDS — the gateway sign-in session expires around 120s."
  • The client WS wait dropped from 600s to ~150s, so the CLI no longer sits on a dead session for 8 minutes after a botched attempt.
  • On timeout AND on a session-expired / no-code callback, it now prints a clear hint: the gateway session expires ~120s, re-run adom-google auth and approve promptly.
  • The SETUP_HINT the installing AI reads got the same ~90s warning, so agent-driven flows post it with the URL.

The other half — bumping the gateway session TTL from ~120s to 600s so the two match — lives on the OAuth gateway container (service-oauth), which is not reachable from a user container. Flagging that for whoever owns the gateway; if the TTL is raised later we can widen the client banner/wait to match. Closing the client-side portion.

John Lauer · 5d ago

Fixed the client side in [email protected].

  • The auth banner no longer says "up to 10 min" — it now reads: "Approve WITHIN ~90 SECONDS — the gateway sign-in session expires around 120s."
  • The client WS wait dropped from 600s to ~150s, so the CLI no longer sits on a dead session for 8 minutes after a botched attempt.
  • On timeout AND on a session-expired / no-code callback, it now prints a clear hint: the gateway session expires ~120s, re-run adom-google auth and approve promptly.
  • The SETUP_HINT the installing AI reads got the same ~90s warning, so agent-driven flows post it with the URL.

The other half — bumping the gateway session TTL from ~120s to 600s so the two match — lives on the OAuth gateway container (service-oauth), which is not reachable from a user container. Flagging that for whoever owns the gateway; if the TTL is raised later we can widen the client banner/wait to match. Closing the client-side portion.

John Lauer · 5d ago

Update: found the ACTUAL root cause and fixed it end-to-end on the gateway (better than the client-only band-aid I closed with).

It was never a config TTL. The gateway simply never pinged its WebSocket clients, so the adom.cloud ingress dropped the IDLE connection at ~120s while the user was still on the Google consent screen. ws.on(close) then wiped the pending registration long before the intended 10-minute STALE_MS, and the late Allow hit "Session Expired". Your measurement of a hard ~120s ceiling was the ingress idle timeout, not a gateway setting.

Fix (john/service-oauth, server.js): added a 30s WebSocket heartbeat (ping every client; terminate ones that stop ponging). adom-google clients already pong (stdlib WS handles the ping opcode), so pending sign-ins now stay alive the full 10 minutes. Deployed live to the gateway.

Proof on the live gateway: opened a WS, registered a state, ponged the pings, and polled /health pending across the old death line:

t+0s pending=1   t+40s pending=1   t+80s pending=1   t+120s pending=1   t+140s pending=1

Before the fix that dropped to 0 at ~120s. (Your own repro, inverted.)

Client side reverted to match reality in [email protected]: the banner/hint now say "you have ~10 minutes" (not the ~90s stopgap), and the client waits the full 600s again.

One follow-up worth filing separately: the gateway container deploy is fragile. Its checkout has no .git and the container has no git auth to git.adom.inc, so the watchdog git fetch auto-update is a silent no-op. I deployed this fix via scp + restart; it persists across crashes/reboots (watchdog restarts the on-disk file), but future gateway commits will NOT auto-deploy until a read deploy key is added on the container. Closing this one as fixed.

Log in to reply.