lakm/nopass
Passwordless authentication helpers for Laravel 10/11. Send secure verification links or one-time passcodes (OTP) to log users in without passwords. Includes configuration, usage examples, testing, and security guidance.
Installation
composer require lakm/nopass
Publish the config file (if needed):
php artisan vendor:publish --provider="LakM\NoPass\NoPassServiceProvider"
Configure Email/SMS Provider Ensure your Laravel app is configured to send emails (e.g., Mailgun, SES) or SMS (e.g., Twilio) for OTP delivery. The package does not bundle these services—you must integrate them separately.
First Use Case: Magic Link Login
use LakM\NoPass\Facades\NoPass;
$user = User::find(1);
$link = NoPass::for($user)
->email()
->routeName('login') // Must match a named route
->generate(['custom' => 'data']); // Optional query params
Mail facade or a queue job).First Use Case: OTP Login
$otp = NoPass::for($user)
->otp()
->generate();
if (NoPass::for($user)->isValid($request->input('otp'))) {
auth()->login($user);
return redirect()->intended('/dashboard');
}
Route Setup
Create a route to handle the magic link (e.g., login-link):
Route::get('/login/{token}', [AuthController::class, 'handleMagicLink'])
->name('login-link');
Implement handleMagicLink to validate the token and log the user in:
public function handleMagicLink($token) {
$user = NoPass::validateToken($token);
if ($user) {
auth()->login($user);
return redirect()->intended('/dashboard');
}
abort(404);
}
$link = NoPass::for($user)
->email()
->routeName('login')
->expires(60) // 60 minutes
->generate(['redirect' => 'dashboard']);
Mail::to($user->email)->send(new MagicLinkNotification($link));
public function validateMagicLink($token) {
$user = NoPass::validateToken($token);
if ($user) {
auth()->login($user);
return redirect()->intended('/dashboard');
}
return back()->withError('Invalid or expired link.');
}
$otp = NoPass::for($user)
->otp()
->length(6)
->expires(5) // 5 minutes
->generate();
// Example with Twilio
$client->messages->create(
$user->phone,
['body' => "Your OTP is: {$otp}"]
);
if (NoPass::for($user)->isValid($request->input('otp'))) {
auth()->login($user);
return redirect()->intended('/dashboard');
}
Combine magic links and OTPs for flexibility:
// In a registration/login controller
if ($request->input('method') === 'email') {
$link = NoPass::for($user)->email()->generate();
// Send email with link
} elseif ($request->input('method') === 'sms') {
$otp = NoPass::for($user)->otp()->generate();
// Send SMS with OTP
}
AuthenticatesUsers trait to include passwordless login options. Example:
public function sendLoginLink(Request $request) {
$user = User::where('email', $request->email)->first();
if ($user) {
$link = NoPass::for($user)->email()->generate();
Mail::to($user->email)->send(new MagicLinkNotification($link));
}
return back()->with('status', 'Login link sent!');
}
Implement rate limiting to prevent abuse (e.g., brute-force OTP guessing):
use Illuminate\Http\Request;
use Illuminate\Cache\RateLimiter;
protected function attemptLogin(Request $request) {
$limiter = app(RateLimiter::class);
$key = $request->ip().'|'.$request->input('email');
if ($limiter->tooManyAttempts($key, 5)) {
abort(429, 'Too many attempts. Try again later.');
}
// Proceed with OTP/magic link logic
}
Offload email/OTP sending to queues to avoid blocking requests:
// Generate link/OTP
$link = NoPass::for($user)->email()->generate();
// Dispatch a job to send the email
SendMagicLinkEmail::dispatch($user, $link);
Define the job:
class SendMagicLinkEmail implements ShouldQueue {
public function handle() {
Mail::to($this->user->email)->send(new MagicLinkNotification($this->link));
}
}
Override defaults in the config or dynamically:
// Config (config/nopass.php)
'email' => [
'expires' => 30, // minutes
],
'otp' => [
'length' => 6,
'expires' => 3, // minutes
],
Or set per-user:
$link = NoPass::for($user)
->email()
->expires(15) // 15 minutes
->generate();
Invalidate tokens after use or on request:
// After successful login
NoPass::for($user)->invalidate();
// Or invalidate all tokens for a user
NoPass::for($user)->invalidateAll();
Track passwordless authentication events:
event(new PasswordlessLoginAttempt($user, $method));
Create an event listener to log to a database or external service.
NoPass::validateToken($token) may fail silently or return null if the token is invalid/expired.$user = NoPass::validateToken($token);
if (!$user) {
abort(404, 'Invalid or expired link.');
}
routeName method requires a named route that exists in your routes/web.php. Using an undefined route will throw an exception.Route::get('/login/{token}', [AuthController::class, 'handleMagicLink'])
->name('login-link');
Mail facade or a queue job to send emails/OTPs. Example for Twilio:
$client = new Client($accountSid, $authToken);
$client->messages->create(
$user->phone,
['body' => "Your OTP is: {$otp}"]
How can I help you explore Laravel packages today?