Skip to content

feat(auth): standalone simple-auth fallback with headless prompt + hub token propagation#106

Merged
antfu merged 3 commits into
mainfrom
feat/simple-auth-fallback
Jul 17, 2026
Merged

feat(auth): standalone simple-auth fallback with headless prompt + hub token propagation#106
antfu merged 3 commits into
mainfrom
feat/simple-auth-fallback

Conversation

@antfubot

Copy link
Copy Markdown
Collaborator

Why

devframe already ships the auth primitivescreateInteractiveAuth (OTP code + magic-link) on the node side, and a client that can exchange a code for a token — but nothing wires them up by default. A tool whose author does nothing runs ungated, and there is no story for a hub to authenticate once and let its plugins ride along.

This adds a built-in fallback: a standalone tool is gated out of the box (opt-out), a browser with no configured auth UI can still get in via a zero-UI prompt, and a hub can keep owning authentication centrally.

What

Standalone (cli / spa / served build)

  • The dev server gates by default: an unset (or true) cli.auth auto-wires the interactive OTP handler and prints its code + magic-link banner once listening. false — or the new composable --no-auth flag — opts out. A DevframeAuthHandler passes straight through. The five built-in plugins keep their explicit auth: false.

Client (connectDevframe)

  • New simpleAuth option (default on). On a refused connection it tries the magic-link URL OTP first, then falls back to a native window.prompt() for the code — zero UI, so devframe stays headless — re-prompting on a wrong/expired code until success or Cancel.
  • It only prompts on a top-level, unframed page. A framed plugin never prompts and instead waits for a hub-propagated token to auto-recover.

Hub / Vite-DevTools

  • No new core hook: a hub authenticates once at the top level and propagates the token down — via the client host context (same-origin), or the new ConnectionMeta.authToken for cross-origin iframes that cannot read the hub's localStorage. Managed plugin connections set simpleAuth: false, so subframes mount already-authorized.

Notes

  • ConnectionMeta.authToken is documented as hub-served, per-frame only (a token in a fetchable JSON is only as safe as the URL serving it) — the standalone __connection.json never carries one.
  • Client token precedence: explicit option → connectionMeta.authTokenlocalStorage → window globals.

Tests cover connection-meta token precedence and adapter auth resolution (default gates / auth: false / --no-auth); the ./client API snapshot is updated for simpleAuth. lint, test (677), typecheck, and build all pass.

This PR was created with the help of an agent.

…b token propagation

Give devframe a built-in authentication fallback so a tool the author has
not explicitly configured is gated out of the box, while a hub can keep
authenticating centrally.

- Standalone dev server gates by default: an unset (or `true`) `cli.auth`
  auto-wires the interactive OTP handler and prints its code banner; `false`
  (or the new `--no-auth` flag) opts out; a handler object passes through.
- Client gains `simpleAuth` (default on): on refusal it tries the magic-link
  OTP, then falls back to a native `window.prompt()` for the code, re-prompting
  until success or cancel. It only prompts on a top-level, unframed page.
- A framed plugin never prompts; it waits for a hub-propagated token. Hubs
  authenticate once at the top level and hand the token down — via the client
  host context same-origin, or a new `ConnectionMeta.authToken` for
  cross-origin iframes that cannot read the hub's localStorage.

Created with the help of an agent.
@netlify

netlify Bot commented Jul 17, 2026

Copy link
Copy Markdown

Deploy Preview for devfra ready!

Name Link
🔨 Latest commit 6c2c3bd
🔍 Latest deploy log https://app.netlify.com/projects/devfra/deploys/6a59a316742c86000858b7a7
😎 Deploy Preview https://deploy-preview-106--devfra.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Comment thread packages/devframe/src/client/rpc.ts Outdated
rpc: undefined!,
}
const authToken = getStoredAuthToken(options.authToken)
const authToken = getStoredAuthToken(options.authToken, connectionMeta.authToken)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const authToken = getStoredAuthToken(options.authToken, connectionMeta.authToken)
const authToken = getStoredAuthToken(options.authToken || connectionMeta.authToken)

so we don't need to change the getStoredAuthToken signaure

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 6c2c3bd — kept getStoredAuthToken's single-arg signature and pass options.authToken || connectionMeta.authToken.

antfubot added 2 commits July 17, 2026 03:34
Convert the prose "Default: x" notes on the auth-related options introduced
in this branch (`simpleAuth`, `otpParam`, `cli.auth`) to the `@default` tag,
matching the convention used elsewhere in the definition types.
…g arg

Pass `options.authToken || connectionMeta.authToken` as the single token
argument instead of adding a second parameter, per review.
@antfu
antfu merged commit 1cf7e66 into main Jul 17, 2026
11 of 12 checks passed
@antfu
antfu deleted the feat/simple-auth-fallback branch July 17, 2026 03:45
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.

2 participants