Skip to content

Email verification

Use mailbox challenges during signup when you want to verify that the user controls the email address before creating or activating their account.

import { createMailboxChallenge } from "@passlock/server";
const tenancyId = "myTenancyId";
const apiKey = "myApiKey";
const result = await createMailboxChallenge({
tenancyId,
apiKey,
email: "jdoe@example.com",
purpose: "signup",
metadata: {
signupId: "signup_123",
},
invalidateOthers: true,
});
// message contains rendered HTML and plain-text email content.
// result.challenge.code is also available if you prefer to render your own email.
const { challengeId, secret, message, email } = result.challenge;
// save this in the user's session or a secure HTTP only cookie
await savePendingChallenge({
flow: "signup",
challengeId,
secret,
email,
});
await emailCodeToUser({ email, message });
import { verifyMailboxChallenge } from "@passlock/server";
// fetch from the user's session or secure cookie
const pending = await loadPendingChallenge({ flow: "signup" });
const verified = await verifyMailboxChallenge({
tenancyId: "myTenancyId",
apiKey: "myApiKey",
challengeId: pending.challengeId,
secret: pending.secret,
code: form.code,
});
if (verified.challenge.purpose !== "signup") {
throw new Error("Unexpected challenge purpose");
}
if (verified.challenge.email !== pending.email) {
throw new Error("Email mismatch");
}
await createUser({
email: verified.challenge.email,
});
await markEmailVerified(verified.challenge.email);
await clearPendingChallenge({ flow: "signup" });

If you also support non-Node.js backends, the same flow is available through the REST API mailbox challenge endpoints.