feat(auth): add --tunnel flag for OAuth login on headless machines#36
feat(auth): add --tunnel flag for OAuth login on headless machines#36danikhan632 wants to merge 3 commits into
Conversation
…ines Adds `notion-cli auth login --tunnel` which uses localtunnel to expose the OAuth callback server via a public HTTPS URL. This enables OAuth login from headless machines or remote servers that don't have a local browser available. Implements a pure Go localtunnel client with no new dependencies. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc205bc018
ℹ️ 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".
| return fmt.Errorf("start tunnel: %w", err) | ||
| } | ||
| defer tun.Close() | ||
| redirectURI = tun.URL + callbackPath |
There was a problem hiding this comment.
Make tunneled OAuth callback unguessable
When tunnel mode is enabled, the redirect is exposed as a public fixed path (<tunnel-url>/callback), so any unsolicited hit that arrives first can be consumed by the callback handler and cause the login flow to fail with state/code errors before the real Notion redirect arrives. This was much less likely in the loopback-only flow, but with a public tunnel URL it becomes a practical denial-of-login vector; use a per-attempt unguessable callback path (or ignore mismatched state and keep waiting) for --tunnel.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch. Fixed in d188c16 — the callback path is now /callback/<random-nonce> when tunnel mode is active, so unsolicited requests to the public URL get a 404 instead of consuming the callback.
When the callback server is exposed via a public tunnel URL, the fixed /callback path is guessable. Generate a random per-attempt nonce so the callback path becomes /callback/<nonce>, preventing unsolicited requests from consuming the callback before the real OAuth redirect arrives. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d188c16a2f
ℹ️ 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".
| if opts.Tunnel { | ||
| fmt.Println("Starting tunnel...") | ||
| tun, err := tunnel.Start(ctx, port) | ||
| if err != nil { | ||
| return fmt.Errorf("start tunnel: %w", err) |
There was a problem hiding this comment.
Check existing auth before opening the tunnel
Starting the tunnel before mcpClient.Initialize makes auth login --tunnel depend on localtunnel availability even when no OAuth flow is needed. If a user is already authenticated (the Initialize call would succeed), this path now fails early at tunnel.Start(...) on offline/restricted networks instead of returning Already authenticated!, which is a regression introduced by this ordering.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in a28e9d5 — added an isAuthenticated pre-check at the top of RunOAuthFlow that tries a quick Initialize before starting any listener or tunnel. If credentials are already valid, it returns immediately without touching localtunnel.
Moves the authentication check before tunnel/listener setup so that `auth login --tunnel` doesn't depend on localtunnel availability when the user already has valid credentials. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@lox Can I get a review on this PR? |
|
Assuming https://github.com/localtunnel/go-localtunnel is out of date? |
Summary
notion-cli auth login --tunnelwhich uses localtunnel to expose the OAuth callback server via a public HTTPS URLMotivation
The current OAuth flow binds the callback server to
127.0.0.1, which requires a local browser to complete the redirect. This doesn't work when SSH'd into a remote server or running in a headless environment without a browser. The--tunnelflag transparently tunnels the callback so the redirect works from any browser on any machine.How it works
--tunnelopens a localtunnel that maps a publichttps://xxx.loca.ltURL to that local portUsage
Without
--tunnel, behavior is unchanged.Test plan
go vet ./...passesnotion-cli auth login --tunnelfrom a remote machinenotion-cli auth loginstill works as before🤖 Generated with Claude Code