jtargosz/laravel-action-otp
jtargosz/laravel-action-otp is a Laravel package for one-time password workflows, offering action-based helpers to generate, send, and verify OTP codes. It fits Laravel's action pattern for clean, reusable authentication and verification flows.
php artisan migrate. Start with config/otp.php, the package routes, ActionOtp, ValidOtpCode, and ConfirmSession.ValidOtpCode, and let the package controllers confirm the session.ActionOtp::identifyUsing(). It controls which identifier the verify and resend routes use, so it is the main integration point for multi-tenant, authenticated-user, or route-model-based flows.Register a server-side identifier resolver once, usually in a service provider:
ActionOtp::identifyUsing(function ($request) {
return $request->user()?->phone
?? $request->route('user')?->phone;
});
The verify and resend routes will use this value and ignore the identifier field in the request body.
Use identifyUsing() for flows where the identifier must not be client-controlled: authenticated user profile changes, admin-triggered verification, tenant-scoped phone/email verification, or signed route parameters.
Return null deliberately when the identifier cannot be resolved. The package answers with an empty response and does not count an attempt. This is useful for avoiding user enumeration, but make sure your frontend treats an empty response as a neutral outcome rather than a validation failure.
Pass a non-blank purpose to ValidOtpCode. A blank purpose now fails validation instead of throwing, so it will surface as a normal validation error. Keep purposes consistent between code generation and validation.
Let the package controllers handle ConfirmSession for code, magic-link, and verify routes. If you verify a ConfirmSession manually outside those routes, set ConfirmSession::SESSION_KEY yourself in the session before relying on it.
In tests, use ActionOtpFake without constructor arguments. Prefer resolving it from the container or the package's fake helper instead of instantiating it directly.
Wrap verify and resend behind authentication and rate limiting where appropriate. The identifier resolver decides the target, but throttling still belongs at the route/middleware layer.
identifyUsing() is global for the verify and resend routes. Make the resolver deterministic per request and avoid side effects; it may be called on both routes.verify and resend once a resolver is set. Update API docs and frontend clients so they do not assume the submitted phone/email is authoritative.null does not increment the attempt counter. Do not use the empty response as proof that an OTP was checked; log or monitor it separately if you need visibility.ConfirmSession is a breaking change in v2.1.0. Code outside the package controllers must set ConfirmSession::SESSION_KEY in the session; otherwise the confirmation will not be recognized.ActionOtpFake no longer accepts a Recorder. Remove the argument from manual instantiations in tests; the constructor change is small but will fail immediately if missed.pl, de were reworded), the ValidOtpCode rule, and the fake used in tests.How can I help you explore Laravel packages today?