Skip to content

spotify: capture OAuth code via local loopback server#317

Merged
drn merged 2 commits into
masterfrom
argus/spotify-cli-shouldnt-auth
Jun 15, 2026
Merged

spotify: capture OAuth code via local loopback server#317
drn merged 2 commits into
masterfrom
argus/spotify-cli-shouldnt-auth

Conversation

@drn

@drn drn commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Replace the manual copy-paste OAuth flow (which used an external relay page as the redirect target) with the standard OAuth loopback redirect. The CLI now starts a local HTTP server on the redirect URI's port, opens the browser to Spotify's consent screen, and captures the authorization code automatically from the callback.

  • authorize() validates SPOTIFY_REDIRECT_URI is a loopback URL with a port, binds a listener on that host:port, sends a cryptographically random CSRF state, and returns the captured code.
  • captureAuthCode() serves the callback, validates state, surfaces error/missing-code cases, shuts down gracefully so the browser response flushes, and guards result delivery with sync.Once against duplicate callbacks. Enforces a 2-minute timeout.
  • Browser is launched via exec.Command (no shell), so the auth URL is never interpreted by zsh.
  • Removed the promptui-based manual code prompt.
  • SPOTIFY_REDIRECT_URI must now be a loopback URL with an explicit port (e.g. http://127.0.0.1:8888/callback), registered as a redirect URI on the Spotify app.

Co-Authored-By: Claude noreply@anthropic.com

Darren Cheng and others added 2 commits June 15, 2026 13:36
Replace the manual copy-paste auth flow (which relied on an external
relay page as the redirect target) with the standard OAuth loopback
redirect. The CLI now starts a local HTTP server on the redirect URI's
port, opens the browser to Spotify's consent screen, and captures the
authorization code automatically from the callback.

- authorize() parses SPOTIFY_REDIRECT_URI, binds a loopback listener on
  its port, sends a random CSRF state, and returns the captured code.
- captureAuthCode() serves the callback, validates state, surfaces
  error/missing-code cases, and enforces a 2-minute timeout.
- Drop inputCode/validateInput and the promptui dependency here.
- SPOTIFY_REDIRECT_URI must now be a loopback URL with an explicit port
  (e.g. http://127.0.0.1:8888/callback) registered on the Spotify app.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Address review findings on the loopback auth flow:

- Open the browser via exec.Command("open", url) instead of building a
  zsh -c string, so the auth URL is never interpreted by a shell.
- Validate that SPOTIFY_REDIRECT_URI is a loopback host (127.0.0.1,
  ::1, or localhost), not just that it has a port — previously a
  non-loopback host would still be sent to Spotify as the redirect.
- Bind the listener to the redirect URI's own host:port so it matches
  the address the browser is redirected to.
- Shut down the callback server gracefully (Shutdown with a 2s grace)
  so the "you can close this tab" response flushes before teardown.
- Guard the result delivery with sync.Once so a browser retry/refresh
  that re-hits the handler can't block on a channel send forever.
- Give net.Listen / randomState failures contextual error messages.

Add tests for isLoopback.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@drn drn force-pushed the argus/spotify-cli-shouldnt-auth branch from 70e8223 to 9f65ea6 Compare June 15, 2026 20:36
@drn drn merged commit b8e56a5 into master Jun 15, 2026
@drn drn deleted the argus/spotify-cli-shouldnt-auth branch June 15, 2026 21:19
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