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.
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
- 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 - The user enters the code into your UI
- Call
allegro.member.validateLoginCode(code)to verify it - On success, a JWT session is issued and
allegro:authenticatedfires onwindowwithdetail.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
);
| Parameter | Type | Required | Description |
|---|---|---|---|
email | string | Yes | The user's email address |
returnUrl | string | No | URL to redirect to after the code is validated. Defaults to the current page. |
data | Record<string, unknown> | No | Custom data to attach to the resulting session |
Response shape:
{
created: boolean; // true if a new audience member was created
jwt: string;
status: 'ok';
}
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.
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');
| Parameter | Type | Required | Description |
|---|---|---|---|
code | string | Yes | The 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:
errorCode | Meaning |
|---|---|
INVALID_OTP | The code is wrong, or no valid code exists for this device |
OTP_EXPIRED | The code has expired — request a new one |
OTP_LOCKED | Too 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.
| Event | Detail | When |
|---|---|---|
allegro:authenticated | { method: 'otp' } | A code was validated successfully |
allegro:jwt-refreshed | MemberJwtPayload | JWT 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>
Related
- Magic Links guide — passwordless authentication via an emailed link
- Social Login guide — OAuth with Google, Apple, and Facebook
- allegro-login-form component — full UI for the auth flow