test(auth): verify expired and fresh MFA login flows end to end
This commit is contained in:
1 parent
d0e0dfeb26
commit
18f1d08bc3
1 file changed
+66
@@ -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 } });
|
||||
});
|
||||
Reference in new issue
Block a user