Skip to content

Passwordless logins

Mailbox challenges also work well for passwordless login flows.

backend/login.ts
import { Passlock, isChallengeRateLimitedError } from "@passlock/server";
const passlock = new Passlock({ ... });
// cpatured in a login form
const 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, message } = result.value.challenge;
// save this in the user's session or a secure HTTP only cookie
await savePendingChallenge({
purpose: "login"
challengeId,
secret,
});
await emailCodeToUser({ email, message });
} else if (isChallengeRateLimitedError(result.error)) {
return showRateLimit(result.error.retryAfterSeconds);
} else {
throw new Error(result.error.message);
}
backend/login.ts
import { Passlock } from "@passlock/server";
const passlock = new Passlock({... });
// fetch from the user's session or secure cookie
const 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 {
return throw new Error(result.error.message);
}