DocumentationAPI v1 · 1.3.0

Packages

OTP widget

@labyrinthe/otp-widget: <labyrinthe-otp> web component and React component for SMS verification, with its server handlers.

Ready-made verification form: number input, code cells, resend with countdown, autofill (Web OTP), light and dark, fr and en. The widget never calls the Labyrinthe API directly: it talks to two routes on your server, which keep the API key.

Version 1.2.0. Source code, examples and changelog: widget-otp folder on GitHub.

Installation#

Shell
npm install @labyrinthe/otp-widget @labyrinthe/connect

How it works#

  1. The browser sends the number to POST /api/otp/send (your server).
  2. Your server calls POST /otp/send with the Node.js SDK and keeps otp_id in an encrypted cookie.
  3. The browser sends the code to POST /api/otp/verify; your server verifies it and calls onVerified (open the session…).

Server side#

Node.js
// lib/otp.ts
import { Labyrinthe } from '@labyrinthe/connect';
import { createOtpHandlers } from '@labyrinthe/otp-widget/server';

export const otp = createOtpHandlers({
  client: () => new Labyrinthe(),              // LABYRINTHE_API_KEY (lsk_test_…: nothing is sent)
  secret: process.env.LABYRINTHE_OTP_SECRET,   // 32+ characters, encrypts the cookie
  cookie: { path: '/api/otp' },
  onVerified: ({ phone, setCookie }) => {
    // The number is verified: trust it here, never in the browser
    return { redirect: '/dashboard' };          // sent back to the widget
  },
});

// Next.js App Router: app/api/otp/send/route.ts and app/api/otp/verify/route.ts
export const runtime = 'nodejs';
export const POST = otp.send;                  // otp.verify in the other route

// Express: app.post('/api/otp/send', otp.express.send); app.post('/api/otp/verify', otp.express.verify);
OptionRole
clientLabyrinthe instance or a function returning one. Required.
secret32 characters or more (LABYRINTHE_OTP_SECRET): encrypts the cookie.
onVerifiedCalled once the number is verified; its return value is sent to the widget. Required.
beforeSend, allowedOriginsRefuse a send (per-IP limit, captcha), restrict origins.
template, locale, webOtpDomain, stripAccents, codeLength, codeTypeOptions passed to POST /otp/send.
exposeTestCodeReturns test_code to the widget (refused when NODE_ENV=production).
storeCustom session store (memoryStore() provided).
'use client';
import { LabyrintheOtp } from '@labyrinthe/otp-widget/react';

export default function VerifyPage() {
  return (
    <LabyrintheOtp
      sendUrl="/api/otp/send"
      verifyUrl="/api/otp/verify"
      locale="fr"
      onVerified={({ data }) => { if (data?.redirect) window.location.assign(data.redirect); }}
      onError={(error) => console.warn(error.code)}
    />
  );
}
AttributeDefaultRole
send-url, verify-url/api/otp/send, /api/otp/verifyYour server routes.
locale, country-code, phonefr, 243, —Language, country code, pre-filled number.
code-length, code-type6, numericCode shape.
theme, headingauto, default titlelight / dark; "" hides the title.
no-auto-submit, no-web-otp—Disable code auto-submit, Web OTP.

Events: labyrinthe-otp:sent, labyrinthe-otp:verified, labyrinthe-otp:error (with code, retryAfterSeconds, adminMessage and until during maintenance). Styling: --lab-otp-primary, --lab-otp-radius… CSS variables and ::part(…).

Maintenance: when OTP sending or verification is off (FEATURE_DISABLED, OTP_SERVICE_DISABLED), the server handlers answer 503 service_unavailable with the platform message and the return date; the widget shows them.