From d068331313d5afb344f8df428a023b13c9e26a55 Mon Sep 17 00:00:00 2001 From: Stan Date: Tue, 25 Aug 2026 17:06:30 +0500 Subject: [PATCH] fix: don't try to mint a key for a brand-new AI/ML API account MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A freshly created passwordless account is inactive (isActive: false) until its first top-up — POST /v1/keys requires USER_SCOPE.active and returns 403 for it, so the sign-up branch's key mint could never succeed. Register the account (still useful — it exists for the user's next visit) but stop there with a clear message pointing at https://aimlapi.com/app to add credit, then /login again to sign in through the code-verification path, which does mint successfully. --- packages/ai/src/auth/oauth/aimlapi.ts | 33 +++++++++++++----------- packages/ai/test/aimlapi-oauth.test.ts | 35 ++++++++++++-------------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/packages/ai/src/auth/oauth/aimlapi.ts b/packages/ai/src/auth/oauth/aimlapi.ts index 3a97838de12..a41665514a8 100644 --- a/packages/ai/src/auth/oauth/aimlapi.ts +++ b/packages/ai/src/auth/oauth/aimlapi.ts @@ -119,24 +119,29 @@ async function loginAimlapi(interaction: ProviderAuthInteraction): Promise { expect(keyAuthHeader).toBe("Bearer session-token"); }); - it("creates a new account without requesting a code when the account does not exist", async () => { + it("creates a new account but does not attempt to mint a key — a fresh account is inactive until its first top-up", async () => { const calls: string[] = []; - vi.stubGlobal( - "fetch", - vi.fn(async (input: string | URL | Request) => { - const url = input instanceof Request ? input.url : String(input); - calls.push(url); - if (url === ACCOUNT_URL) return jsonResponse({ action: "sign-up" }); - if (url === PASSWORDLESS_URL) return jsonResponse({ token: "new-session-token", exp: 9999999999 }); - if (url === KEYS_URL) return jsonResponse({ key: "aiml-new-key", id: "key-2" }); - throw new Error(`Unexpected request: ${url}`); - }), - ); - - const credential = await aimlapiOAuth.login({ - signal: neverAbortedSignal, - prompt: async () => "new-user@example.com", - notify: () => {}, + const fetchMock = vi.fn(async (input: string | URL | Request) => { + const url = input instanceof Request ? input.url : String(input); + calls.push(url); + if (url === ACCOUNT_URL) return jsonResponse({ action: "sign-up" }); + if (url === PASSWORDLESS_URL) return jsonResponse({ token: "new-session-token", exp: 9999999999 }); + throw new Error(`Unexpected request: ${url}`); }); + vi.stubGlobal("fetch", fetchMock); - expect(credential).toMatchObject({ access: "aiml-new-key" }); - expect(calls).toEqual([ACCOUNT_URL, PASSWORDLESS_URL, KEYS_URL]); + await expect( + aimlapiOAuth.login({ + signal: neverAbortedSignal, + prompt: async () => "new-user@example.com", + notify: () => {}, + }), + ).rejects.toThrow(/Account created for new-user@example.com.*run \/login again/); + expect(calls).toEqual([ACCOUNT_URL, PASSWORDLESS_URL]); }); it("rejects an account linked to a third-party sign-in provider", async () => {