Summary
On Windows, apollo auth login (v2.0.0, apollo-windows-x64.exe) always fails: the browser opens Apollo's authorize page showing
The requested redirect uri is malformed or doesn't match client redirect URI.
Nothing is wrong with the registered client — the URL the browser receives is truncated.
Root cause
openBrowser in src/oauth.ts launches the browser on win32 via:
spawnSync('cmd', ['/c', 'start', '', url])
Node only quotes arguments containing whitespace, so the auth URL is passed to cmd.exe unquoted — and cmd treats every unquoted & in the query string as a command separator. The browser therefore receives only:
https://mcp.apollo.io/mcp/oauth_metadata/redirect_to_authorize?client_id=<id>
i.e. everything from &redirect_uri=... onward is cut off (the remaining query params are executed as no-op cmd commands). With no redirect_uri in the request, the server correctly rejects it with the misleading "malformed or doesn't match" error.
Because cmd itself exits 0, result.status !== 0 never triggers, so the "Could not open browser automatically. Visit: ..." fallback with the full URL is never shown — the user has no way to recover.
Reproduction
Windows 11, apollo-windows-x64.exe v2.0.0 from the GitHub release:
Browser opens → Apollo error page as above, 100% reproducible. Verified the truncation independently: registering a client via POST /api/v1/oauth/applications/register_oauth_client with redirect_uris: ["http://localhost:3421/callback"] succeeds, and visiting the full authorize URL manually works fine (login completes, token saved).
Workaround (for other Windows users)
Force the browser-open to fail so the CLI prints the full URL, then open it manually:
$env:PATH = ""; & "$env:LOCALAPPDATA\Programs\apollo-cli\apollo.exe" auth login
# copy the printed URL, then in another terminal:
Start-Process "<printed url>"
Suggested fix
Avoid cmd's metacharacter parsing entirely, e.g.:
process.platform === 'win32'
? spawnSync('rundll32', ['url.dll,FileProtocolHandler', url])
(no shell involved, handles & fine), or keep cmd /c start but escape the URL (url.replace(/[&^|<>]/g, '^$&')), or shell out to PowerShell's Start-Process. Also worth printing the URL unconditionally (many CLIs do) so a failed auto-open is always recoverable.
Summary
On Windows,
apollo auth login(v2.0.0,apollo-windows-x64.exe) always fails: the browser opens Apollo's authorize page showingNothing is wrong with the registered client — the URL the browser receives is truncated.
Root cause
openBrowserinsrc/oauth.tslaunches the browser on win32 via:Node only quotes arguments containing whitespace, so the auth URL is passed to
cmd.exeunquoted — andcmdtreats every unquoted&in the query string as a command separator. The browser therefore receives only:i.e. everything from
&redirect_uri=...onward is cut off (the remaining query params are executed as no-op cmd commands). With noredirect_uriin the request, the server correctly rejects it with the misleading "malformed or doesn't match" error.Because
cmditself exits 0,result.status !== 0never triggers, so the "Could not open browser automatically. Visit: ..." fallback with the full URL is never shown — the user has no way to recover.Reproduction
Windows 11,
apollo-windows-x64.exev2.0.0 from the GitHub release:Browser opens → Apollo error page as above, 100% reproducible. Verified the truncation independently: registering a client via
POST /api/v1/oauth/applications/register_oauth_clientwithredirect_uris: ["http://localhost:3421/callback"]succeeds, and visiting the full authorize URL manually works fine (login completes, token saved).Workaround (for other Windows users)
Force the browser-open to fail so the CLI prints the full URL, then open it manually:
Suggested fix
Avoid
cmd's metacharacter parsing entirely, e.g.:(no shell involved, handles
&fine), or keepcmd /c startbut escape the URL (url.replace(/[&^|<>]/g, '^$&')), or shell out to PowerShell'sStart-Process. Also worth printing the URL unconditionally (many CLIs do) so a failed auto-open is always recoverable.