- How do I install and set up spatie/laravel-one-time-passwords in a Laravel app?
- Install it with Composer using composer require spatie/laravel-one-time-passwords, then publish and run the migration that creates the one-time password table and publish the config file. Add the package trait to your authenticatable model so it gains the sendOneTimePassword() and attemptLoginUsingOneTimePassword() methods. That is the entire setup surface: a migration, a config file, a mail notification and one trait on your user model. No external service, sidecar or new datastore is required, so it drops into a standard Laravel app cleanly.
- Does the package include a ready-made Livewire login component?
- Yes. It ships with an opinionated Livewire component that provides the email entry screen and the code entry screen for passwordless login. If Flux is installed, the component automatically switches to the Flux OTP input component instead of a standard text input. You can use the component as-is for a near-zero-frontend pilot, or skip it entirely and build your own flow on the underlying methods.
- How do I send one-time passwords via SMS instead of email?
- By default an OTP is a six-digit code delivered through a mail notification, but that notification is built to be extended so it can go out over SMS or any other channel. Swap the notification or add a channel for your SMS provider while keeping the same generation, expiry and consumption logic. Everything else in the flow, including single-use enforcement and the attemptLoginUsingOneTimePassword() call, stays identical across channels.
- How long is an OTP valid and can I change the expiry time?
- The default lifetime is two minutes, and it is configurable in the package's config file. Because the window is short, your transactional mail latency matters: if email takes longer than that to arrive, codes expire before users can type them. Raising the expiry buys tolerance for slow delivery but weakens the security story, so validate your provider's p99 latency before committing to the default.
- Can I build a custom OTP login flow without the Livewire component?
- Yes. The package exposes simple methods on your user model, such as sendOneTimePassword() and attemptLoginUsingOneTimePassword(), plus a result enum so you can react to success and failure cases. That lets you build a fully branded flow in your own controller, Blade view, Inertia page or API endpoint. You keep the same security behaviour without adopting the bundled Livewire UI.
- Which Laravel and Livewire versions does spatie/laravel-one-time-passwords support?
- The package is Laravel-native and has tracked current framework releases, with Laravel 13 and Livewire 4 support added inside the 1.x line. Livewire is optional: install it only if you want the bundled login component. Always check the Composer constraints on Packagist against your app's PHP and Laravel versions before upgrading, since minor releases can move the requirement.
- Are OTPs hashed in the database, and do I need to clean up expired codes?
- Codes are stored in a table created by the package's published migration, but hashing at rest and automatic purging are not clearly documented, so verify both in the source before going live. If expired rows are not purged automatically, schedule a cleanup job or prune command for the table. This is a must-verify item for a security review, together with whether user enumeration is possible when a code is requested.
- How does the package protect against brute force and replay of one-time passwords?
- Each code is short-lived and single-use, and the package applies rate limiting with translated error messages when attempts are exceeded. It also binds a code to the originating IP and user agent and enforces same-origin requests, with the enforce_same_origin config fixed to actually be respected in 1.1.0. Version 1.1.1 changed Timebox to return early on successful consumption, which shows active refinement of replay handling, but you should still verify atomic single-use consumption on your database engine.
- Why do some users get a different origin or validation error when logging in with an OTP?
- The package pins each code to the requesting IP address and user agent, so legitimate users on mobile networks, VPNs, corporate proxies or after a browser auto-update can fail closed with a validation error. Note that the translation key was renamed from request_did_not_match to different_origin within 1.x, which can break assertions in your tests and change user-facing messages. Treat identity binding as a product decision: keep it for tighter security, or relax it if support contacts become the bigger cost.
- Is spatie/laravel-one-time-passwords production-ready?
- It is a narrow, well-documented Spatie package with CI, PHPStan, a changelog and regular releases, but adoption is still modest at roughly 183 GitHub stars and no declared dependents, so treat 1.x as credible but young. Because it sits directly on the login path, a defect is an account-takeover class incident, which justifies a threat model, focused code review and penetration test rather than a normal pull request review. Keep an eye on minor releases too, since behavioural and translation-string changes have shipped inside 1.x.