Skip to content

th-bc624a: Big Smooth UI sign-in (click-to-login th over the web UI)#216

Merged
brentrager merged 1 commit into
mainfrom
smooth-ui-login
Jul 14, 2026
Merged

th-bc624a: Big Smooth UI sign-in (click-to-login th over the web UI)#216
brentrager merged 1 commit into
mainfrom
smooth-ui-login

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

To log the Big Smooth daemon's th into Smoo AI you currently have to SSH to the host and run th auth login (which opens a localhost-callback browser flow). A user viewing the Big Smooth web UI remotely (e.g. over a tailscale-served origin) has no way to sign in from the browser.

Solution

Route the same browser OAuth2 + PKCE flow through the daemon itself, so a "Sign in to Smoo AI" button in the web UI is all that's needed.

New routes on the Big Smooth axum server (smooth-bigsmooth):

  • GET /auth/login — derives the daemon's own callback URL from the request (X-Forwarded-Proto header, default http, + Host), mints a PKCE pair + CSRF state, stashes the verifier in a single-use in-memory store (10-min TTL, pruned on insert), and 302s to smoo.ai/cli-login?redirect_uri=…&state=…&code_challenge=…&code_challenge_method=S256.
  • GET /auth/callback — single-use-removes the state (CSRF/expiry → fail closed), exchanges the code at smoo.ai/api/token, persists a user Credentials to ~/.smooth/auth/smooai-user.json (the same file th's user-authed API calls read), and renders a success/failure HTML page. Surfaces an upstream error= (user cancelled) as a friendly page.
  • GET /api/auth/status{ loggedIn, user, orgId }; never errors on a missing session file.

Web UI (smooth-web): a minimal sidebar affordance polls /api/auth/status and shows "Signed in as …" or a plain-anchor Sign in to Smoo AI button (plain <a>, so the browser follows the daemon's 302 rather than client-routing).

The PKCE / URL-building / callback-parsing / token-exchange primitives are copied from smooth-cli (auth::{browser_login,pkce}) because smooth-bigsmooth can't depend on smooth-cli (the CLI depends on the lib, not vice-versa). A ponytail: comment marks the duplication for extraction if a third consumer appears. Credentials/CredentialsStore come from the shared smooai-client-shared crate (same dep + auth feature the CLI uses).

Security notes

  • CSRF state is single-use and validated before the code is touched; unknown/expired state fails closed. Verifiers and tokens are never logged.
  • 10-minute TTL on pending logins, pruned on every insert.
  • Known risk (flagged for review): smoo.ai/cli-login may whitelist only 127.0.0.1 redirect_uris (the CLI flow always uses a loopback callback). If so, this daemon-origin redirect_uri (e.g. https://smooth.<tailnet>.ts.net/auth/callback) will be rejected at the smoo.ai side on first real use, and we'd need a redirect_uri allowlist entry on the smoo.ai side (or a device-code flow instead). No redirect_uri validation exists in this repo — it lives entirely on the smoo.ai side.

Tests

cargo test -p smooai-smooth-bigsmooth auth_login — redirect_uri derivation (Host + X-Forwarded-Proto, first-hop, missing-Host), pending-store insert / TTL-expiry / single-use removal / prune-on-insert, callback parsing incl. state-mismatch / missing-code / access-denied / percent-decode, authorize-URL building, and the RFC 7636 challenge vector. All green.

🤖 Generated with Claude Code

… over the daemon)

Lets a user viewing the Big Smooth web UI remotely (e.g. over tailscale)
log `th` into Smoo AI by clicking a button instead of SSHing in to run
`th auth login`. Adds GET /auth/login (mint PKCE + CSRF state, 302 to
smoo.ai/cli-login), GET /auth/callback (single-use state validation +
token exchange, persist the user session), and GET /api/auth/status.
The callback URL is derived from Host + X-Forwarded-Proto; the PKCE
primitives are copied from smooth-cli (bigsmooth can't depend on the CLI).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1091e3c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@smooai/smooth Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@brentrager brentrager merged commit 5865150 into main Jul 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant