Introducing mailbox challenges
New feature Passlock now supports mailbox challenges, a server-side feature for building email one-time code flows without rebuilding the awkward security and lifecycle pieces yourself.
This is aimed at the cases teams keep needing even when passkeys are the long-term goal:
- verifying email ownership during signup
- passwordless login when passkeys are not available
- confirming a new email address before updating an account
What a mailbox challenge is
Section titled “What a mailbox challenge is”A mailbox challenge is an email verification flow with a little more structure than “generate a six-digit code and hope for the best”.
When you create a challenge, Passlock returns:
challengeIdto identify the challengesecretfor your app to keep server-sidecodefor you to deliver by emailmessage.htmlandmessage.textif you want ready-made email content
The user receives the code, enters it into your app, and your backend verifies the attempt using all three parts: challengeId, secret, and code.
That detail matters. The emailed code alone is not enough.
Why we built it
Section titled “Why we built it”Email one-time codes look simple until you try to ship them properly.
You need challenge expiry, retry handling, invalidation of older outstanding codes, rate limiting, consistent verification, and a way to reduce the risk of treating an intercepted code as sufficient proof on its own.
Mailbox challenges package those moving parts into a small API so you can focus on your product flow instead of rebuilding verification plumbing.
Typical flow
Section titled “Typical flow”The flow is straightforward:
- Your backend creates a mailbox challenge for a purpose like
signup,login, oremail-change. - Your app stores
challengeIdandsecretin a server-side session or HTTP-only cookie. - Your mailer sends the code to the user, using Passlock’s rendered message or your own template.
- The user submits the code.
- Your backend verifies the challenge and checks the returned
purpose,email, and any expected local user context before completing the action.
If you need to restore an in-progress flow, you can also read a challenge without exposing the secret or code.
Using @passlock/server
Section titled “Using @passlock/server”If you are already using the Passlock server library, the basic shape looks like this:
import { createMailboxChallenge, verifyMailboxChallenge,} from "@passlock/server";
const created = await createMailboxChallenge({ tenancyId: "myTenancyId", apiKey: "myApiKey", email: "jdoe@example.com", purpose: "login", invalidateOthers: true,});
await savePendingLoginSession({ challengeId: created.challenge.challengeId, secret: created.challenge.secret,});
await sendEmail({ to: created.challenge.email, html: created.challenge.message.html, text: created.challenge.message.text,});
const pending = await readPendingLoginSession();
const verified = await verifyMailboxChallenge({ tenancyId: "myTenancyId", apiKey: "myApiKey", challengeId: pending.challengeId, secret: pending.secret, code: form.code,});
if (verified.challenge.purpose !== "login") { throw new Error("Unexpected challenge purpose");}
await completeLoginForEmail(verified.challenge.email);The same feature is also available over raw HTTP if you are not using Node.js.
Why Passlock does not send the email for you
Section titled “Why Passlock does not send the email for you”Passlock creates the challenge and renders the message content, but the email still comes from your system.
That is deliberate:
- the email should come from your domain
- you keep control over deliverability and branding
- you can either send the rendered HTML/text directly or generate your own template from the raw code
Where mailbox challenges fit
Section titled “Where mailbox challenges fit”Mailbox challenges are not a replacement for passkeys. They cover a different part of the authentication surface.
Passkeys remain the stronger default for ongoing authentication. Mailbox challenges are useful when you need to prove mailbox ownership, offer a passwordless fallback, or verify account changes that are naturally email-centric.
In practice, many applications will use both:
- passkeys for primary authentication
- mailbox challenges for onboarding, recovery, or account-change verification