fix(config): trim ADMIN_API_KEY to prevent trailing whitespace auth failures

This commit is contained in:
coo1estguy
2026-09-08 15:45:36 +05:30
parent 167b2d9a7b
commit d293685ca6
3 changed files with 19 additions and 2 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "notifkit",
"version": "0.1.5",
"version": "0.1.6",
"description": "Self-hosted notification infrastructure. One call delivers to email, SMS, push, and webhook — routed by preference, quiet hours, and consent.",
"license": "MIT",
"author": "devkitshq",
+5 -1
View File
@@ -38,7 +38,11 @@ export const baseConfigSchema = z.object({
HOST: z.string().default("127.0.0.1"),
REDIS_URL: z.string().url().default("redis://localhost:6379"),
DATABASE_URL: z.string().url().default("postgres://platform:platform@localhost:5432/notifkit"),
ADMIN_API_KEY: z.string().optional(),
// Trimmed because the incoming bearer token is trimmed before comparison, so
// an untrimmed value here could never match it. `set KEY=value && cmd` on
// Windows puts a trailing space in the variable, which otherwise turns every
// admin request into a 401 that reads like a wrong key.
ADMIN_API_KEY: z.string().trim().optional(),
WORKER_CONCURRENCY: z.coerce.number().int().min(1).default(10),
QUEUE_MAX_LEN: z.coerce.number().int().min(1).default(10000000),
DB_MAX_CONNECTIONS: z.coerce.number().int().min(1).default(2),
+13
View File
@@ -58,6 +58,19 @@ describe("extractAuthToken", () => {
expect(extractAuthToken(req as any)).toBe("my-token-with-spaces");
});
// `set ADMIN_API_KEY=key && cmd` on Windows puts a trailing space in the
// variable. The token side is trimmed, so if the configured side were not,
// the two could never match and every admin request would 401.
it("matches a configured key that carries the whitespace a shell added", async () => {
const { readBaseConfig } = await import("@/config/index.js");
const config = readBaseConfig({ ADMIN_API_KEY: "supersecretkey " } as NodeJS.ProcessEnv);
const token = extractAuthToken({ headers: { authorization: "Bearer supersecretkey" } } as any);
expect(config.ADMIN_API_KEY).toBe("supersecretkey");
expect(token).toBe(config.ADMIN_API_KEY);
});
it("prioritizes Bearer authorization header over x-api-key if both are present", () => {
const req = {
headers: {