3neti/form-handler-otp

OTP verification handler for form flow system

Maintainers

Package info

github.com/3neti/form-handler-otp

pkg:composer/3neti/form-handler-otp

Transparency log

Statistics

Installs: 1 442

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v1.2.3 2026-08-09 15:56 UTC

This package is auto-updated.

Last update: 2026-08-09 15:59:38 UTC


README

3neti/form-handler-otp adds mobile one-time-password verification to 3neti/form-flow. It delegates OTP generation, delivery, expiry, attempt tracking, and verification to a configured Txtcmdr service.

Requirements

  • PHP 8.2 or newer
  • Laravel 12 or 13
  • Form Flow 1.8 or newer
  • Inertia Laravel 2 or 3 in applications that render the published Vue page

Installation

composer require 3neti/form-handler-otp
php artisan otp-handler:install --no-interaction

The package service provider registers the otp handler automatically. The install command publishes the package configuration and Vue page.

Configuration

Publish the configuration independently when needed:

php artisan vendor:publish --tag=otp-handler-config

Configure the Txtcmdr endpoint and bearer token in the host environment:

TXTCMDR_API_URL=https://txtcmdr.example
TXTCMDR_API_TOKEN=
TXTCMDR_CONNECT_TIMEOUT=5
TXTCMDR_TIMEOUT=15
TXTCMDR_VERIFY_SSL=true
OTP_HANDLER_DRIVER=txtcmdr

OTP_MAX_RESENDS=3
OTP_RESEND_COOLDOWN=30

Do not commit the API token. The handler sends it only as the bearer token for Txtcmdr requests.

Form Flow contract

Add an otp step after a step that collects mobile:

[
    'handler' => 'otp',
    'config' => [
        'purpose' => 'onboarding.account',
        'max_resends' => 3,
        'resend_cooldown' => 30,
        'digits' => 6,
        'ui_variant' => 'compact',
    ],
]

The handler reads the mobile number from the current Form Flow session. It fails before contacting Txtcmdr if no mobile number has been collected.

Rendering the handler has no delivery side effect. The claimant explicitly selects Send verification code. The handler then:

  1. creates a challenge through POST /api/v1/otp/challenges;
  2. stores only the returned challenge reference in the session;
  3. enables verification and the throttled resend control.

On submission, it verifies through POST /api/v1/otp/challenges/{challenge}/verify. A successful verification clears the challenge and delivery-control session state, then returns:

[
    'mobile' => '+639171234567',
    'verified_at' => '2026-07-31T15:00:00+08:00',
    'reference_id' => 'flow-123',
    'verification_reference' => '01K...',
    'verification_purpose' => 'onboarding.account',
]

The raw code is never returned as Form Flow result data. Hosts must validate the structured proof against the expected purpose and claimant identity before executing a protected workflow.

User interface

The published Vue page supports Form Flow's default, compact, and immersive UI variants. It uses the shared Form Flow screen and action components, accepts numeric input, submits the nested data.otp_code payload, and focuses the code input on entry.

Delivery safeguards

  • Verification identifiers are isolated by Form Flow reference in the session.
  • Opening or refreshing the page cannot send an SMS.
  • Successful codes are one-time because Txtcmdr is the verification authority and local session state is cleared after acceptance.
  • Resend count and cooldown are enforced by the server handler, not only by the browser.
  • Provider rejection reasons are mapped to sanitized validation messages.
  • A missing verification session or mobile number fails closed.
  • Hosts should still rate-limit Form Flow endpoints by authenticated principal, session, mobile reference, and source address.

Testing

composer test
composer pint -- --test
composer audit

The package suite fakes HTTP and verifies the request, session, resend, provider-rejection, expiry, and UI render contracts without sending SMS.

License

MIT