Skip to main content

One-Time Codes

One-time codes provide passwordless authentication — the user enters their email, receives a six-digit code, and types it back in to authenticate without a password.

Unlike magic links, the code is entered on the same device that requested it, so authentication completes synchronously. There is no cross-tab polling — the device that requests the code is the device that signs in.

Just want a login form?

If you don't need to build the UI yourself, the <allegro-login-form> web component handles the entire one-time code flow out of the box — drop one tag on your page and you're done.

How It Works

  1. Call allegro.member.requestLoginCode(email) — Allegro emails a six-digit code to that address and creates the audience member if they do not already exist
  2. The user enters the code into your UI
  3. Call allegro.member.validateLoginCode(code) to verify it
  4. On success, a JWT session is issued and allegro:authenticated fires on window with detail.method === 'otp'

Requesting a Code

await allegro.member.requestLoginCode(
'[email protected]',
'https://example.com/account', // optional: where to redirect after auth
{ plan: 'monthly' }, // optional: custom data attached to the session
);
ParameterTypeRequiredDescription
emailstringYesThe user's email address
returnUrlstringNoURL to redirect to after the code is validated. Defaults to the current page.
dataRecord<string, unknown>NoCustom data to attach to the resulting session

Response shape:

{
created: boolean; // true if a new audience member was created
jwt: string;
status: 'ok';
}
Codes expire and resends invalidate older codes

Each code is valid for 30 minutes. Requesting a new code invalidates any previous code for the session — only the most recently emailed code works.

Requests are rate limited

Requesting a code is limited to 3 requests per email per minute. Beyond that, the request is rejected with a rate-limit error. Surface a "try again shortly" message rather than retrying automatically.

Validating a Code

const { jwt, return_url, audience_member_created } =
await allegro.member.validateLoginCode('123456');
ParameterTypeRequiredDescription
codestringYesThe six-digit code the user typed

Response shape:

{
message: string;
jwt: string;
return_url: string | null; // the returnUrl from the original request, if any
audience_member_created: boolean;
sessions_authenticated: string[];
}

On success the session JWT is stored automatically and an allegro:authenticated event fires. On failure, validation throws an AllegroApiError whose errorCode is one of:

errorCodeMeaning
INVALID_OTPThe code is wrong, or no valid code exists for this device
OTP_EXPIREDThe code has expired — request a new one
OTP_LOCKEDToo many incorrect attempts — the code is locked, request a new one
try {
await allegro.member.validateLoginCode(code);
} catch (error) {
if (error.errorCode === 'OTP_LOCKED') {
// Prompt the user to request a fresh code
} else {
// Show "that code wasn't right" and let them retry
}
}

SDK Events

All events are dispatched on window as CustomEvent instances.

EventDetailWhen
allegro:authenticated{ method: 'otp' }A code was validated successfully
allegro:jwt-refreshedMemberJwtPayloadJWT was refreshed successfully
allegro:logout(none)User was logged out
window.addEventListener('allegro:authenticated', (event) => {
if (event.detail.method === 'otp') {
// User is now authenticated — update your UI
}
});

Using the allegro-login-form Component

The <allegro-login-form> web component handles the full one-time code flow automatically — no manual SDK calls needed:

<allegro-login-form publisher-name="Example News"></allegro-login-form>