Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/vercel-basic-auth-callbacks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@plainbrew/vercel-basic-auth": minor
---

feat: add `beforeAuth` and `afterAuth` callback options to `basicAuth`
66 changes: 65 additions & 1 deletion packages/vercel-basic-auth/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { afterEach, describe, expect, test } from "vitest";
import { afterEach, describe, expect, test, vi } from "vitest";

import { basicAuth } from "./index";

Expand Down Expand Up @@ -194,3 +194,67 @@ describe("認証ヘッダーのバリデーション", () => {
expect(res?.status).toBe(401);
});
});

describe("beforeAuth コールバック", () => {
test("beforeAuth が false を返すとき 401 を返す", () => {
const req = makeRequest(makeBasicAuthHeader(USERNAME, PASSWORD));
const res = basicAuth(req, {
username: USERNAME,
password: PASSWORD,
beforeAuth: () => false,
});
expect(res?.status).toBe(401);
});

test("beforeAuth が true を返すとき通常の認証フローに進む", () => {
const req = makeRequest(makeBasicAuthHeader(USERNAME, PASSWORD));
expect(
basicAuth(req, { username: USERNAME, password: PASSWORD, beforeAuth: () => true }),
).toBeNull();
});

test("beforeAuth が false を返すとき認証ヘッダーなしでも 401 を返す", () => {
const req = makeRequest();
const res = basicAuth(req, {
username: USERNAME,
password: PASSWORD,
beforeAuth: () => false,
});
expect(res?.status).toBe(401);
});

test("NODE_ENV=development (dev=false) のときも beforeAuth は呼ばれる", () => {
process.env.NODE_ENV = "development";
const beforeAuth = vi.fn(() => false);
const req = makeRequest();
const res = basicAuth(req, { username: USERNAME, password: PASSWORD, beforeAuth });
expect(beforeAuth).toHaveBeenCalled();
expect(res?.status).toBe(401);
});
});

describe("afterAuth コールバック", () => {
test("afterAuth が false を返すとき 401 を返す", () => {
const req = makeRequest(makeBasicAuthHeader(USERNAME, PASSWORD));
const res = basicAuth(req, {
username: USERNAME,
password: PASSWORD,
afterAuth: () => false,
});
expect(res?.status).toBe(401);
});

test("afterAuth が true を返すとき null を返す", () => {
const req = makeRequest(makeBasicAuthHeader(USERNAME, PASSWORD));
expect(
basicAuth(req, { username: USERNAME, password: PASSWORD, afterAuth: () => true }),
).toBeNull();
});

test("認証失敗のとき afterAuth は呼ばれない", () => {
const afterAuth = vi.fn(() => true);
const req = makeRequest(makeBasicAuthHeader(USERNAME, "wrong"));
basicAuth(req, { username: USERNAME, password: PASSWORD, afterAuth });
expect(afterAuth).not.toHaveBeenCalled();
});
});
22 changes: 22 additions & 0 deletions packages/vercel-basic-auth/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ export type BasicAuthOptions = {
* @default false
*/
dev?: boolean;
/**
* 組み込みの環境判定後、認証チェック前に呼ばれるコールバック
* - true を返すと通常の認証フローに進む
* - false を返すと認証失敗 (401) を返す
*/
Comment on lines +16 to +20
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

beforeAuth の JSDoc が実装順序と逆です。

Line 17 は「環境判定後」となっていますが、実装は Line 50 で環境判定より前に beforeAuth を実行しています。利用者向け仕様説明が誤るため修正してください。

修正案(JSDoc のみ)
   /**
-   * 組み込みの環境判定後、認証チェック前に呼ばれるコールバック
+   * 組み込みの環境判定前に呼ばれるコールバック
    * - true を返すと通常の認証フローに進む
    * - false を返すと認証失敗 (401) を返す
    */
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* 組み込みの環境判定後、認証チェック前に呼ばれるコールバック
* - true を返すと通常の認証フローに進む
* - false を返すと認証失敗 (401) を返す
*/
/**
* 組み込みの環境判定前に呼ばれるコールバック
* - true を返すと通常の認証フローに進む
* - false を返すと認証失敗 (401) を返す
*/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vercel-basic-auth/src/index.ts` around lines 16 - 20, The JSDoc for
beforeAuth is incorrect about when it's invoked; update the comment to state
that beforeAuth is executed before the built-in environment check (i.e., called
prior to any environment gating) and that returning true continues the normal
auth flow while false returns a 401. Locate the beforeAuth parameter/option in
this module (the beforeAuth callback referenced in the exported auth setup) and
change the JSDoc text to reflect "called before environment check" and keep the
existing behavior description (true -> proceed, false -> return 401).

beforeAuth?: (request: Request) => boolean;
/**
* 認証成功後に呼ばれるコールバック
* - true を返すと通過する
* - false を返すと認証失敗 (401) を返す
*/
afterAuth?: (request: Request) => boolean;
};

export function basicAuth(
Expand All @@ -22,6 +34,8 @@ export function basicAuth(
password: authPassword,
vercelEnvTarget = "only-production",
dev = false,
beforeAuth,
afterAuth,
}: BasicAuthOptions,
): Response | null {
function unauthorized() {
Expand All @@ -33,6 +47,10 @@ export function basicAuth(
});
}

if (beforeAuth && !beforeAuth(request)) {
return unauthorized();
}

if (process.env.NODE_ENV === "development") {
if (!dev) {
return null;
Expand Down Expand Up @@ -79,5 +97,9 @@ export function basicAuth(
return unauthorized();
}

if (afterAuth && !afterAuth(request)) {
return unauthorized();
}

return null;
}
Loading