diff --git a/server/src/__tests__/agent-auth-jwt.test.ts b/server/src/__tests__/agent-auth-jwt.test.ts index 1cc8a60a..c2505b29 100644 --- a/server/src/__tests__/agent-auth-jwt.test.ts +++ b/server/src/__tests__/agent-auth-jwt.test.ts @@ -3,12 +3,14 @@ import { createLocalAgentJwt, verifyLocalAgentJwt } from "../agent-auth-jwt.js"; describe("agent local JWT", () => { const secretEnv = "PAPERCLIP_AGENT_JWT_SECRET"; + const betterAuthSecretEnv = "BETTER_AUTH_SECRET"; const ttlEnv = "PAPERCLIP_AGENT_JWT_TTL_SECONDS"; const issuerEnv = "PAPERCLIP_AGENT_JWT_ISSUER"; const audienceEnv = "PAPERCLIP_AGENT_JWT_AUDIENCE"; const originalEnv = { secret: process.env[secretEnv], + betterAuthSecret: process.env[betterAuthSecretEnv], ttl: process.env[ttlEnv], issuer: process.env[issuerEnv], audience: process.env[audienceEnv], @@ -16,6 +18,7 @@ describe("agent local JWT", () => { beforeEach(() => { process.env[secretEnv] = "test-secret"; + delete process.env[betterAuthSecretEnv]; process.env[ttlEnv] = "3600"; delete process.env[issuerEnv]; delete process.env[audienceEnv]; @@ -26,6 +29,8 @@ describe("agent local JWT", () => { vi.useRealTimers(); if (originalEnv.secret === undefined) delete process.env[secretEnv]; else process.env[secretEnv] = originalEnv.secret; + if (originalEnv.betterAuthSecret === undefined) delete process.env[betterAuthSecretEnv]; + else process.env[betterAuthSecretEnv] = originalEnv.betterAuthSecret; if (originalEnv.ttl === undefined) delete process.env[ttlEnv]; else process.env[ttlEnv] = originalEnv.ttl; if (originalEnv.issuer === undefined) delete process.env[issuerEnv]; @@ -57,6 +62,22 @@ describe("agent local JWT", () => { expect(verifyLocalAgentJwt("abc.def.ghi")).toBeNull(); }); + it("falls back to BETTER_AUTH_SECRET when PAPERCLIP_AGENT_JWT_SECRET is absent", () => { + delete process.env[secretEnv]; + process.env[betterAuthSecretEnv] = "fallback-secret"; + vi.setSystemTime(new Date("2026-01-01T00:00:00.000Z")); + const token = createLocalAgentJwt("agent-1", "company-1", "claude_local", "run-1"); + expect(typeof token).toBe("string"); + + const claims = verifyLocalAgentJwt(token!); + expect(claims).toMatchObject({ + sub: "agent-1", + company_id: "company-1", + adapter_type: "claude_local", + run_id: "run-1", + }); + }); + it("rejects expired tokens", () => { process.env[ttlEnv] = "1"; vi.setSystemTime(new Date("2026-01-01T00:00:00.000Z")); diff --git a/server/src/agent-auth-jwt.ts b/server/src/agent-auth-jwt.ts index 6ec696b9..728461b0 100644 --- a/server/src/agent-auth-jwt.ts +++ b/server/src/agent-auth-jwt.ts @@ -26,7 +26,7 @@ function parseNumber(value: string | undefined, fallback: number) { } function jwtConfig() { - const secret = process.env.PAPERCLIP_AGENT_JWT_SECRET; + const secret = process.env.PAPERCLIP_AGENT_JWT_SECRET?.trim() || process.env.BETTER_AUTH_SECRET?.trim(); if (!secret) return null; return {