From a9a688e772ae0d64dbe623ec93af846993a4ecce Mon Sep 17 00:00:00 2001 From: Mario Tarosso Date: Wed, 19 Aug 2026 15:30:27 +0100 Subject: [PATCH] [ENG-3568] Point `login` at the approval page, not the API root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `login` printed {apiOrigin}/activate. That origin is the API, not the dashboard, and /activate already serves the team-seat "set a password" page — so following the link landed on an unrelated screen with nothing to approve. Points at monitor/pulse/device instead, which redirects to the dashboard SPA, and carries the code in the query so following the link is a single confirmation rather than retyping it. Co-Authored-By: Claude --- src/login.ts | 5 ++++- tests/login.test.ts | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/login.ts b/src/login.ts index 01c3d3d..f295323 100644 --- a/src/login.ts +++ b/src/login.ts @@ -78,7 +78,10 @@ export async function login( interval: number; }; - const verificationUri = `${new URL(base).origin}/activate`; + // Points at the API, which redirects to the dashboard SPA — the CLI only + // knows the API origin, and the approval page lives on the app. The code + // travels in the link so following it is a single confirmation. + const verificationUri = `${base}/device?code=${encodeURIComponent(userCode)}`; onPrompt(userCode, verificationUri); const deadline = now() + expiresIn * 1000; diff --git a/tests/login.test.ts b/tests/login.test.ts index 0c0a6a0..ea1a202 100644 --- a/tests/login.test.ts +++ b/tests/login.test.ts @@ -47,7 +47,12 @@ describe('login', () => { const result = await login(config(), onPrompt, { fetchImpl: fetchImpl as never, ...noSleep }); expect(result.status).toBe('approved'); - expect(onPrompt).toHaveBeenCalledWith('WDJB-MJHT', 'https://api.patchstack.com/activate'); + // The API redirects this to the dashboard SPA; the code rides along so + // following the link is one confirmation rather than a retype. + expect(onPrompt).toHaveBeenCalledWith( + 'WDJB-MJHT', + 'https://api.patchstack.com/monitor/pulse/device?code=WDJB-MJHT', + ); // Both fields: approving rotates the one secret block-logs use too, so // leaving apiKey behind would break block-log reporting.