Skip to main content
Run the check while a visitor fills in your registration form. Your server applies its registration policy when they submit. A visitor who finishes the form before measurement completes sees the SDK’s waiting UI; a visitor with a current measurement can proceed directly to the policy check. The Next.js and PostgreSQL example includes a working registration page at /register, alongside redemption and checkout. All pages share one browser client and prepared measurement.

Bind registration before login

A new visitor has no account ID yet. Create a pending registration ID on your server and associate it with an opaque, HttpOnly application session. Use that pending ID as accountId and the server session’s stable ID as sessionId in resolveContext. The example’s POST /api/demo/registration creates or reuses this pending registration. It accepts no account ID from the browser. The endpoint checks the request origin, refuses already signed-in accounts and preserves the pending ID on retries. After that endpoint sets the session, the browser refreshes the SDK’s context and submits the form:
This snippet uses the endpoints and client included in the downloadable app. Its form also preserves attempt IDs, displays errors and exposes an explicit restart for an expired or unresolved challenge. A pending registration is permission to attempt registration only. The example’s redemption and checkout actions require a signed-in session attached to an existing account. Creating the account record does not silently grant those permissions.

Apply the registration policy

The register action in lib/actions.mjs:
  1. Validates and normalizes the email address.
  2. Confirms the pending registration belongs to the current server session.
  3. Locks that pending registration and checks whether its ID or normalized email already has an account.
  4. Requests a ceremony for a measurement whose verdict is not uncontradicted, unless the saved ceremony has passed.
  5. Creates the account record and saves the action receipt in the same database transaction.
The database has a unique email index. The resource key includes the normalized email, so concurrent attempts for that address are serialized. A lock on the pending registration also prevents one session from creating different accounts with simultaneous submissions. These are sample application rules. A passed ceremony does not override the email or session checks, and the policy runs again after the ceremony. Heretic’s findings remain unchanged.

Connect your authentication system

The local example stores an account record without verifying mailbox ownership, creating credentials or signing the visitor in. Connect those steps to your existing authentication system. Heretic measurement and ceremony results do not establish ownership of an email address. Use your own pending-registration session, CSRF protection, input limits and existing uniqueness rules. Keep application sessions and credentials on the server. If your authentication provider is external, save a provisioning or email task in an outbox and deliver it with a stable idempotency key; do not make the external call inside commit. Once your authentication system signs the visitor in, rotate the application session as usual and call client.status() again. Background requests that started before this refresh cannot restore the older SDK account context.

Exercise the example

  • Select Guest, enter a test address and create the account. Retry the same attempt to read its existing receipt.
  • Select Guest again to start another registration, or use a second browser session. Submit the same normalized email to check duplicate handling.
  • Set HERETIC_FIXTURE_VERDICT=contradicted, restart and use a fresh browser session to exercise the local ceremony.
  • Create a competing registration while the first ceremony is pending. Completing the ceremony must not create a second account for the same email.
The shared action contract covers timeouts, retries, context changes and retention. A single-use widget is also available for existing signup forms.