benbjurstrom/otpz
otpz is a Laravel package for passwordless authentication using one-time passwords. Generate and validate secure OTP codes, send them by email, and add rate limiting and expiry controls to your login flow with minimal setup.
Architecture fit
benbjurstrom/otpz is a narrowly scoped, opinionated OTP issuance/verification package for Laravel — migration-backed code storage, routes/controllers for request and verify, and mail-based delivery. It fits applications that need a first-party "email me a code" flow (passwordless login step-up, email verification, low-assurance 2FA) without adopting a full identity provider. It is not a general auth framework: if the roadmap includes TOTP, WebAuthn, SMS failover, or per-tenant policy configuration, expect to wrap or fork rather than configure.
Integration feasibility
Low-to-moderate effort. Composer install, publish config/migrations/views/lang, run migration, wire the generated routes or call the service directly. v0.7.0 is additive for new adopters: localization is a new publishable asset set, and Laravel 13 support widens the illuminate/* constraint. The ip_address nullable fix only affects the published migration stub — a greenfield install gets it automatically, but it is not retroactive for anyone who already published migrations in a prior version.
Technical risk
ip_address change corrects the stub. Existing deployments need a hand-written ALTER/->change() migration; without it, environments diverge silently between fresh installs and upgraded installs — a classic "works in CI, fails on the legacy prod DB" trap.ip_address collection is now optional at the schema level. Storing IPs has GDPR/CCPA and retention implications; nullable is the right default, but the policy decision (log or don't) is ours, not the package's.Key questions
composer.json constraint?Stack fit Strong for a standard Laravel app on MySQL/Postgres with queued mail already configured. The package assumes mail as the delivery channel and a relational store for codes; it does not assume a specific frontend, so it slots behind both Blade and an SPA/API. Apps already using Laravel's notification or queue infrastructure inherit those operational properties for free.
Migration path
ip_address column and confirm intent.ip_address is already NOT NULL in a shared environment, ship an explicit corrective migration before the package bump, and backfill or default any existing rows. Do not rely on re-publishing.lang/ into the app, diff against any existing overrides, and decide whether translations live in the package namespace or the app's. Prefer app-owned overrides so future package releases don't silently overwrite tuned copy.Compatibility
Confirm the Laravel 13 constraint does not drop the version we actually run — widened support is usually additive, but a raised floor is the failure mode to check in composer.json before upgrading. Also verify PHP version floor and any illuminate/* component constraints against our lockfile.
Sequencing Config and policy decisions (IP capture, code length, TTL, throttle thresholds) → migrations → delivery channel and queue wiring → localization → integration tests for expired/throttled/replayed codes → canary in staging with real mail provider.
Maintenance Low ongoing code maintenance; the real cost is version hygiene on a pre-1.0 dependency and ownership of published assets (migrations, config, lang, views) that no longer update with the package. Budget a recurring review at each release to diff published files.
Support Community-supported with a small maintainer base. Assume no SLA. For anything auth-adjacent, we should be prepared to patch locally — meaning the integration should be thin and wrapped behind our own service/interface so a fork or replacement is a contained change.
Scaling
Two pressure points: row growth in the OTP table (needs a scheduled prune of expired/consumed codes; without it the table grows unbounded and index performance degrades) and mail throughput at login spikes (send via queue, and confirm the provider's rate limits before a launch event). Verification is a single indexed lookup — cheap. Rate limiting is the package's job only insofar as it's configured; per-IP and per-identifier throttles need explicit tuning, and the nullable ip_address means IP-based throttling is only as good as our decision to record it.
Failure modes
NOT NULL violation in production only.composer update.Ramp-up Half a day for a Laravel-fluent engineer on a greenfield install; add a day if localization and corrective migrations are in scope, and another if the team has no prior OTP flow to model against. The package's small surface is the main mitigant — the learning burden sits in the surrounding decisions (throttle policy, retention, mail reliability), not in the code.
How can I help you explore Laravel packages today?