test(auth): verify expired and fresh MFA login flows end to end

This commit is contained in:
Clintchiz committed 2026-08-26 19:23:52 +05:30
1 parent d0e0dfeb26
commit 18f1d08bc3
1 file changed
+66
+66
View File
@@ -0,0 +1,66 @@
import { expect, test } from "bun:test";
import { createContext } from "@wrnexus/core";
import { createAuthEngine } from "../src/engine.ts";
import { createAuthHttpHandlers } from "../src/http/index.ts";
import { MemoryAuthStore } from "../src/stores/memory.ts";
import { generateTotp } from "../src/totp/index.ts";
test("HTTP login creates a usable MFA challenge; expired requests require a new login", async () => {
let time = 1_720_000_000_000;
const engine = createAuthEngine({
store: new MemoryAuthStore(),
secret: "mfa-full-flow-test-secret-longer-than-thirty-two-characters",
clock: { now: () => time },
});
const user = await engine.register({ email: "flow@example.test", password: "StrongPassword123" });
const setup = await engine.beginTotp(user.user!.id);
expect(
await engine.confirmTotp(
user.user!.id,
setup.credentialId,
await generateTotp(setup.secret, { timestamp: time }),
),
).toBe(true);
const handlers = createAuthHttpHandlers({ engine });
const context = (path: string, body: unknown) => {
const req = new Request(`https://sso.example.test${path}`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
});
return createContext(req, new URL(req.url));
};
const login = async () => {
const response = await handlers.login(
context("/api/auth/login", {
identifier: "flow@example.test",
password: "StrongPassword123",
}),
);
expect(response.status).toBe(401);
const result = await response.json();
expect(result.code).toBe("mfa-required");
expect(result.mfaExpiresAt).toBe(time + 300_000);
return result;
};
const old = await login();
time += 300_001;
const expired = await handlers.completeMfa(
context("/api/auth/mfa/complete", {
mfaToken: old.mfaToken,
method: "totp",
code: await generateTotp(setup.secret, { timestamp: time }),
}),
);
expect((await expired.json()).code).toBe("mfa-transaction-expired");
const fresh = await login();
const success = await handlers.completeMfa(
context("/api/auth/mfa/complete", {
mfaToken: fresh.mfaToken,
method: "totp",
code: await generateTotp(setup.secret, { timestamp: time }),
}),
);
expect(success.status).toBe(200);
expect(await success.json()).toMatchObject({ ok: true, user: { id: user.user!.id } });
});