spatie/laravel-login-link
Spatie Laravel Login Link adds a Blade component to render one-click login links for seeded users in local development. Great for admin areas and teams: pick a user/role without remembering credentials. Restricts usage by allowed hosts (defaults to localhost).
Installation:
composer require spatie/laravel-login-link
Publish the config file (optional):
php artisan vendor:publish --provider="Spatie\LoginLink\LoginLinkServiceProvider"
Configuration:
Edit config/login-link.php to define your test users:
'users' => [
'admin@example.com' => [
'password' => 'password',
'role' => 'admin',
],
'editor@example.com' => [
'password' => 'editor123',
'role' => 'editor',
],
],
First Use Case: Add the login link to your Blade template:
<x-login-link />
Or generate a direct link for a specific user:
route('login-link', ['user' => 'admin@example.com']);
Dynamic User Management: Fetch users from a database and dynamically generate login links:
$users = User::where('is_test_user', true)->get();
foreach ($users as $user) {
echo '<a href="' . route('login-link', ['user' => $user->email]) . '">' . $user->email . '</a>';
}
Role-Based Access: Use middleware to restrict login links to specific roles:
Route::middleware(['role:admin'])->get('/admin-login', function () {
return view('admin.login-links', [
'users' => config('login-link.users'),
]);
});
Customizing the Login Link:
Extend the default LoginLink component:
<x-login-link :user="$user" :customText="'Login as ' . $user->name" />
Integration with Testing:
Use in phpunit.xml for automated testing:
<env name="LOGIN_LINK_USER" value="test@example.com" />
Then access it in tests:
$user = config('login-link.users.' . env('LOGIN_LINK_USER'));
API-Based Login Links: Generate signed login links for API consumers:
$signedLink = route('login-link', ['user' => 'api@example.com'], false);
$signedLink = Str::of($signedLink)->append('?signature=' . hash_hmac('sha256', $signedLink, config('app.key')));
CSRF Protection:
The login link bypasses CSRF protection by default. If your app requires strict CSRF checks, ensure the login-link route is excluded in VerifyCsrfToken middleware:
protected $except = [
'login-link',
];
Session Hijacking:
The package uses a signed route parameter. Ensure your app key (APP_KEY) is secure and rotated periodically. Avoid committing it to version control.
Password Complexity: If your app enforces strong passwords, ensure test users comply or disable validation for test routes:
Route::middleware(['throttle:60'])->group(function () {
// Regular routes
});
Caching Issues:
If using Laravel's cache, clear it after updating config/login-link.php:
php artisan cache:clear
Invalid Links:
Check the login-link route in routes/web.php for typos or missing middleware. Verify the users array in config/login-link.php has valid email-password pairs.
Authentication Failures:
Ensure the auth middleware is not interfering with the login-link route. The package relies on manual authentication, not Laravel's default auth system.
Environment-Specific Config: Override config per environment:
config(['login-link.users' => []]); // Clear default users in .env.testing
Custom Authentication Logic:
Override the Spatie\LoginLink\LoginLink class to add custom logic (e.g., 2FA):
public function authenticate(Request $request, User $user)
{
if (!$this->verifyTwoFactor($request, $user)) {
return redirect()->back()->with('error', '2FA required');
}
auth()->login($user);
}
Database-Backed Users:
Replace the config array with a database query in the LoginLinkServiceProvider:
$this->app->bind('config', function () {
return collect(User::where('is_test_user', true)->get())
->keyBy('email')
->mapWithKeys(function ($user) {
return [$user->email => [
'password' => $user->password,
'role' => $user->role,
]];
})->toArray();
});
Custom Blade Component: Extend the default component to add features like:
<x-login-link :user="$user" :showRole="true" :showCopyButton="true" />
Update the component logic in app/View/Components/LoginLink.php.
Rate Limiting: Add rate limiting to prevent brute-force attacks:
Route::middleware(['throttle:5,1'])->get('/login-link', [LoginLinkController::class, 'login']);
How can I help you explore Laravel packages today?