Passwordless logins
Mailbox challenges also work well for passwordless login flows.
Generate and email the challenge
Section titled “Generate and email the challenge”createMailboxChallenge sends the challenge email by default. Pass sendEmail: false only if you want to send the rendered email yourself.
import { Passlock, isChallengeRateLimitedError } from "@passlock/server";
const passlock = new Passlock({ ... });
// captured in a login formconst email = "...";
const user = await findUserByEmail(email);if (!user) { throw new Error("Account not found");}
const result = await passlock.createMailboxChallenge({ email, userId: user.id, purpose: "login", // any pending "login" challenges for this userId will be nuked invalidateOthers: true,});
if (result.success) { const { challengeId, secret } = result.value.challenge;
// save this in the user's session or a secure HTTP only cookie await savePendingChallenge({ purpose: "login", challengeId, secret, });} else if (isChallengeRateLimitedError(result.error)) { return showRateLimit(result.error.retryAfterSeconds);} else { throw new Error(result.error.message);}Verify the code and create a session
Section titled “Verify the code and create a session”import { Passlock } from "@passlock/server";
const passlock = new Passlock({... });
// fetch from the user's session or secure cookieconst pendingChallenge = await loadPendingChallenge({ purpose: "login" });
const result = await passlock.verifyMailboxChallenge({ challengeId: pendingChallenge.challengeId, secret: pendingChallenge.secret, code: form.code, // the user submitted this});
if (result.success) { const { challenge } = result.value; await createLoginSession(challenge.userId);} else { throw new Error(result.error.message);}