mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 22:02:16 +00:00
fix(auth): offer the provider re-proof to a browser only
The MFA status read listed oidc among the proof methods for a Bearer caller too, although the provider round trip stamps a browser session and nothing else, and the API contract says a token is never offered it. The status read now leaves it out on the Bearer path.
This commit is contained in:
1 parent
fc117d7cd9
commit
6fb50b01b8
2 files changed
+37
-3
No files matched your search
@@ -27,7 +27,7 @@ import { recentProofMethods } from "@/lib/auth/second-factor";
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export const GET = apiHandler(async () => {
|
||||
const { user } = await requireAuth();
|
||||
const { user, authMethod } = await requireAuth();
|
||||
|
||||
const [recoveryCodesRemaining, webauthn, proofMethods] = await Promise.all([
|
||||
countRemainingRecoveryCodes(user.id),
|
||||
@@ -50,7 +50,12 @@ export const GET = apiHandler(async () => {
|
||||
passkeyNudgeDismissed: Boolean(user.passkeyUpgradeNudgeDismissed),
|
||||
// The ways this account can confirm it is you, the list the recent-proof
|
||||
// refusal names. The passkey card offers exactly these before adding one,
|
||||
// so an account without a password is not handed a password field.
|
||||
proofMethods,
|
||||
// so an account without a password is not handed a password field. The
|
||||
// provider round trip stamps a browser session and nothing else, so a
|
||||
// token is never offered it.
|
||||
proofMethods:
|
||||
authMethod === "cookie"
|
||||
? proofMethods
|
||||
: proofMethods.filter((method) => method !== "oidc"),
|
||||
});
|
||||
});
|
||||
@@ -59,6 +59,7 @@ vi.mock("@/lib/auth/oidc", async (importOriginal) => {
|
||||
});
|
||||
|
||||
const oidc = await import("@/lib/auth/oidc");
|
||||
const { hashToken } = await import("@/lib/auth/hmac");
|
||||
|
||||
const USER_ID = "user-oidc-reproof";
|
||||
const SUB = "idp-sub-reproof";
|
||||
@@ -313,4 +314,32 @@ describe("confirming at the identity provider", () => {
|
||||
expect(back.searchParams.get("reproof")).toBe("failed");
|
||||
expect(oidc.discoverOidcMetadata).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("is listed on the status read for the browser, never for a token", async () => {
|
||||
const { GET } = await import("@/app/api/auth/me/mfa/route");
|
||||
const status = async () => {
|
||||
const res = await (GET as unknown as RouteFn)(
|
||||
new NextRequest("http://localhost:3000/api/auth/me/mfa"),
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
return ((await res.json()) as { data: { proofMethods: string[] } }).data
|
||||
.proofMethods;
|
||||
};
|
||||
|
||||
await startSession(HOUR);
|
||||
expect(await status()).toEqual(["oidc"]);
|
||||
|
||||
cookieJar.clear();
|
||||
const raw = `hlk_mfastatus${"0".repeat(64 - "mfastatus".length)}`;
|
||||
await getPrismaClient().apiToken.create({
|
||||
data: {
|
||||
userId: USER_ID,
|
||||
name: "device",
|
||||
tokenHash: hashToken(raw),
|
||||
permissions: ["*"],
|
||||
},
|
||||
});
|
||||
headerJar.set("authorization", `Bearer ${raw}`);
|
||||
expect(await status()).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user