diff --git a/functions/src/__tests__/providers-dataverse.test.js b/functions/src/__tests__/providers-dataverse.test.js index f9d0284..5c9e268 100644 --- a/functions/src/__tests__/providers-dataverse.test.js +++ b/functions/src/__tests__/providers-dataverse.test.js @@ -1351,4 +1351,25 @@ describe("9. validateStaticToken", () => { expect(result).toBe(false); }); + + it("logs the status and body of a non-200, with the token scrubbed", async () => { + const warn = jest.spyOn(console, "warn").mockImplementation(() => {}); + mockFetch.mockResolvedValueOnce( + mockResponse({ + status: 403, + statusText: "Forbidden", + textBody: '{"status":"ERROR","message":"Bad api key test-token"}', + }) + ); + + await dataverseProvider.validateStaticToken(auth); + + expect(warn).toHaveBeenCalledTimes(1); + const [message] = warn.mock.calls[0]; + expect(message).toContain("403"); + expect(message).toContain(SERVER_URL); + expect(message).toContain("Bad api key [redacted]"); + expect(message).not.toContain("test-token"); + warn.mockRestore(); + }); }); diff --git a/functions/src/providers/dataverse.ts b/functions/src/providers/dataverse.ts index 7e2bac1..1e9d2ba 100644 --- a/functions/src/providers/dataverse.ts +++ b/functions/src/providers/dataverse.ts @@ -423,7 +423,21 @@ export const dataverseProvider: StorageProvider = { }); // Never throw on a non-200 -- a bad/expired token is simply "not valid", // not an exceptional condition. - return response.status === 200; + if (response.status === 200) return true; + + // Log what the installation actually said. The caller collapses every + // non-200 into "Invalid API token", so without this a real 401, a WAF + // 403, and an outage 5xx are indistinguishable after the fact. The body + // is truncated (a WAF block page can be large) and scrubbed of the token + // in case an installation echoes the key back in its error message. + let body = ""; + try { + body = (await response.text()).split(auth.token).join("[redacted]").slice(0, 300); + } catch { + // Body is diagnostic only; an unreadable one still leaves the status. + } + console.warn(`dataverse validateStaticToken: ${serverUrl}/api/users/:me returned ${response.status}: ${body}`); + return false; }, // Reads the token's expiry from the one endpoint that reports it, GET