fix(server): remove LOBU_NO_AUTH, add /api/exchange-token PAT handoff#827
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughThis PR removes legacy ChangesTransition from LOBU_NO_AUTH to token exchange
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a95508728a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| const auth = await createAuth(c.env, c.req.raw); | ||
| const ctx = await auth.$context; | ||
| const session = await ctx.internalAdapter.createSession(authInfo.userId); |
There was a problem hiding this comment.
Restrict PAT exchange before minting full sessions
When a user creates a scoped PAT (for example mcp:read for CI or an external MCP client), this endpoint now accepts that token and mints an unrestricted Better Auth web session for the PAT's user. That bypasses the existing authSource === 'pat' guard on privileged web-only actions such as creating new server tokens, because the follow-up request is authenticated as a normal session rather than as the original scoped PAT. The exchange should be limited to the bootstrap/local handoff token or otherwise enforce high-trust scopes/purpose before creating a browser session.
Useful? React with 👍 / 👎.
| 'Path=/', | ||
| 'HttpOnly', | ||
| 'SameSite=Lax', | ||
| `Max-Age=${60 * 60 * 24 * 7}`, | ||
| ]; | ||
| if (isHttps) cookieParts.push('Secure'); | ||
| c.header('Set-Cookie', cookieParts.join('; ')); | ||
|
|
There was a problem hiding this comment.
Preserve cross-subdomain cookie attributes
In hosted deployments with AUTH_COOKIE_DOMAIN enabled, normal Better Auth sign-in sets the session cookie for the shared domain so browsers on org subdomains can call the canonical app/API host. This manually constructed cookie is host-only because it never adds the configured Domain, so a token exchanged on acme.lobu.ai will not authenticate subsequent credentialed requests to app.lobu.ai, breaking the cross-subdomain flow that the auth config explicitly supports.
Useful? React with 👍 / 👎.
LOBU_NO_AUTH=1 attributed every request to a fixed bootstrap-user/org pair without checking any credential. Its only safety was the boot guard that refused to start unless the listener was bound to loopback — but the guard knew only about the listener, not about out-of-process proxies (Tailscale Funnel, ngrok, cloudflared, nginx) that reverse-proxy public traffic into the loopback bind. With any such proxy running, the "loopback-only personal mode" guarantee silently broke: every public request landed authenticated as the bootstrap user with owner role. Rather than paper over the gap with proxy detection (forwarded-* headers, opt-out env vars, version-dependent tailscale CLI probes), drop the shortcut entirely. The embedded local-Lobu experience keeps working through the existing bootstrap PAT (ensureBootstrapPat() already mints one and writes it to <LOBU_DATA_DIR>/bootstrap-pat.txt on first boot). To make that PAT ergonomic for browser-based clients (macOS menu-bar app, deep links from the operator's terminal), add GET /api/exchange-token?token=<PAT>&next=<path>: validates the PAT, mints a Better Auth session via internalAdapter.createSession(), signs the session token matching Better Auth's cookie format, and 302s to next. Next is restricted to relative paths to prevent open-redirect abuse; Referrer-Policy: no-referrer keeps the PAT out of the next page's Referer. The cookie name picks up the __Secure- prefix from the canonical baseURL (resolveBaseUrl), so it matches whatever Better Auth would set during normal sign-in even when TLS is terminated by a reverse proxy. The companion SPA hook (?lobu_token=<PAT> on any URL) shipped in owletto#157 — submodule pointer bumped to 0eaaa9aa. Files removed: utils/loopback.ts (only ever used by the no-auth boot guards), docs/plans/personal-mode-auth.md (the design doc for the removed mode).
a955087 to
4da1a6b
Compare
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Summary
`LOBU_NO_AUTH=1` attributed every request to a fixed bootstrap user/org without checking any credential. Its only safety was the boot guard that refused to start unless the listener was bound to loopback — but that guard knew only about the listener, not about out-of-process proxies (Tailscale Funnel, ngrok, cloudflared, nginx) that reverse-proxy public traffic into the loopback bind. With any such proxy running, the "loopback-only personal mode" guarantee silently broke: every public request landed authenticated as the bootstrap user with owner role.
Rather than paper over the gap with proxy detection (forwarded-* headers, opt-out env vars, version-dependent tailscale CLI probes), drop the shortcut entirely. The embedded local-Lobu experience keeps working through the existing bootstrap PAT (`ensureBootstrapPat()` already mints one and writes it to `<LOBU_DATA_DIR>/bootstrap-pat.txt` on first boot).
To make that PAT ergonomic for browser-based clients (macOS menu-bar app, deep links from the operator's terminal):
Net diff: −531 lines (mostly the deleted `docs/plans/personal-mode-auth.md` and `utils/loopback.ts`, plus the bypass branch in `workspace/multi-tenant.ts`).
Files removed
Test plan
Out-of-repo impact
None — `LOBU_NO_AUTH=1` had no documented external consumers besides the in-repo Mac app, which is updated in the bundled submodule bump.
Summary by CodeRabbit
New Features
Chores