laravel-auth-suite maintained by mwy
Mwy Laravel Auth Suite
Reusable Laravel authentication package using plain Blade views, Tailwind CSS CDN, two-factor authentication, account settings, and device management.
This package is designed to give Laravel projects a ready-to-use authentication module without Fortify, Jetstream, Livewire, Inertia, or Laravel UI.
Features
- Login, register, logout, forgot password, reset password, and optional email verification
- Plain Blade views with Tailwind CSS CDN
- Clean application layout, navbar, footer, dashboard, profile, settings, and security pages
- Two-factor authentication with two selectable methods: Authenticator app or Email OTP
- Authenticator app QR code and TOTP verification
- Email OTP delivery through Laravel mail/SMTP configuration
- OTP challenge, recovery codes, and recovery code regeneration
- Encrypted two-factor secret and encrypted recovery codes
- Device/session management with the ability to disconnect other devices
- Login rate limiting and session regeneration
- Configurable route prefix, redirects, registration, password reset, and email verification
- Install command that copies routes, controllers, middleware, services, traits, views, config, and migrations into the Laravel application
Requirements
- PHP 8.2+
- Laravel 10, 11, or 12
- A standard
userstable withname,email, andpassword
Installation
Install from Packagist:
composer require mwy/laravel-auth-suite
php artisan auth:install --force
php artisan migrate
php artisan optimize:clear
The default installer copies application-ready files into your Laravel app and appends a readable route block into routes/web.php.
Update Existing Installation
When updating the package in an existing Laravel project, use:
composer update mwy/laravel-auth-suite -W
php artisan auth:install --force
php artisan migrate
php artisan optimize:clear
Installation From GitHub
If the repository is not installed from Packagist, add a VCS repository to the consuming project's composer.json:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/mwy/laravel-auth-suite"
}
]
}
Then run:
composer require mwy/laravel-auth-suite
php artisan auth:install --force
php artisan migrate
Install Command
Primary command:
php artisan auth:install
Useful options:
php artisan auth:install --force
php artisan auth:install --skip-app-files
--forceoverwrites generated package files in the application.--skip-app-filespublishes config and migrations only, without copying controllers, middleware, services, traits, views, or the route block.
The package also auto-installs once during Laravel package discovery. To disable auto-install before requiring the package, set:
AUTH_SUITE_AUTO_INSTALL=false
Generated Files
Default install copies these files into the Laravel application:
app/Http/Controllers/Auth
app/Http/Middleware/Auth
app/Services/Auth
app/Models/Traits
resources/views/Auth
resources/views/layouts
resources/views/layouts/partials
config/auth-suite.php
database/migrations
routes/web.php
After copying the route block to routes/web.php, the installer sets load_routes to false in config/auth-suite.php to avoid duplicate vendor and application routes.
User Model
Add the two-factor trait to App\Models\User.
If you use the copied application trait after running the default installer:
use App\Models\Traits\HasTwoFactorAuthentication;
class User extends Authenticatable
{
use HasTwoFactorAuthentication;
}
If you use package-managed vendor files instead:
use Mwy\LaravelAuthSuite\Traits\HasTwoFactorAuthentication;
class User extends Authenticatable
{
use HasTwoFactorAuthentication;
}
The package uses forceFill for package-managed fields, so it works with guarded or fillable model rules.
Device Management
Device management reads Laravel's sessions table. Use database sessions for the complete feature:
SESSION_DRIVER=database
Then run:
php artisan migrate
The package includes a guarded sessions migration. If the application already has a sessions table, the migration skips creation.
Users can open /settings/devices to:
- Review active sessions
- See the current device
- Disconnect one other device
- Disconnect all other devices after current-password confirmation
Two-factor Methods
Users can choose one of two MFA methods from /settings/security.
Authenticator App
The authenticator method shows a QR code and verifies time-based OTP codes from an authenticator application. Recovery codes are generated after successful setup.
Email OTP
The email OTP method sends a one-time code to the user's email address using Laravel's mailer. Configure SMTP in the consuming Laravel application's .env:
MAIL_MAILER=smtp
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USERNAME=your-smtp-username
MAIL_PASSWORD=your-smtp-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=no-reply@example.com
MAIL_FROM_NAME="${APP_NAME}"
Email OTP settings can be adjusted from config/auth-suite.php:
AUTH_SUITE_EMAIL_OTP_LENGTH=6
AUTH_SUITE_EMAIL_OTP_EXPIRES_MINUTES=10
AUTH_SUITE_EMAIL_OTP_RESEND_COOLDOWN_SECONDS=60
AUTH_SUITE_EMAIL_OTP_SUBJECT="Your verification code"
Configuration
Publish config manually if needed:
php artisan vendor:publish --tag=auth-suite-config
Main options in config/auth-suite.php:
return [
'auto_install' => env('AUTH_SUITE_AUTO_INSTALL', true),
'load_routes' => env('AUTH_SUITE_LOAD_ROUTES', true),
'route_prefix' => env('AUTH_SUITE_ROUTE_PREFIX', ''),
'middleware' => ['web'],
'two_factor_enabled' => env('AUTH_SUITE_TWO_FACTOR_ENABLED', true),
'two_factor_default_method' => env('AUTH_SUITE_TWO_FACTOR_DEFAULT_METHOD', 'authenticator'),
'recovery_codes_count' => env('AUTH_SUITE_RECOVERY_CODES_COUNT', 8),
'app_name_for_qr' => env('AUTH_SUITE_QR_APP_NAME', env('APP_NAME', 'Laravel')),
'email_otp_length' => env('AUTH_SUITE_EMAIL_OTP_LENGTH', 6),
'email_otp_expires_minutes' => env('AUTH_SUITE_EMAIL_OTP_EXPIRES_MINUTES', 10),
'email_otp_resend_cooldown_seconds' => env('AUTH_SUITE_EMAIL_OTP_RESEND_COOLDOWN_SECONDS', 60),
'email_otp_subject' => env('AUTH_SUITE_EMAIL_OTP_SUBJECT', 'Your verification code'),
'redirect_after_login' => env('AUTH_SUITE_REDIRECT_AFTER_LOGIN', '/dashboard'),
'redirect_after_logout' => env('AUTH_SUITE_REDIRECT_AFTER_LOGOUT', '/login'),
'enable_registration' => env('AUTH_SUITE_ENABLE_REGISTRATION', true),
'enable_password_reset' => env('AUTH_SUITE_ENABLE_PASSWORD_RESET', true),
'enable_email_verification' => env('AUTH_SUITE_ENABLE_EMAIL_VERIFICATION', true),
'tailwind_cdn_enabled' => env('AUTH_SUITE_TAILWIND_CDN_ENABLED', true),
];
Example .env:
SESSION_DRIVER=database
AUTH_SUITE_ROUTE_PREFIX=
AUTH_SUITE_REDIRECT_AFTER_LOGIN=/dashboard
AUTH_SUITE_REDIRECT_AFTER_LOGOUT=/login
AUTH_SUITE_TWO_FACTOR_ENABLED=true
AUTH_SUITE_TWO_FACTOR_DEFAULT_METHOD=authenticator
AUTH_SUITE_RECOVERY_CODES_COUNT=8
AUTH_SUITE_EMAIL_OTP_LENGTH=6
AUTH_SUITE_EMAIL_OTP_EXPIRES_MINUTES=10
AUTH_SUITE_EMAIL_OTP_RESEND_COOLDOWN_SECONDS=60
AUTH_SUITE_EMAIL_OTP_SUBJECT="Your verification code"
AUTH_SUITE_ENABLE_REGISTRATION=true
AUTH_SUITE_ENABLE_PASSWORD_RESET=true
AUTH_SUITE_ENABLE_EMAIL_VERIFICATION=true
AUTH_SUITE_TAILWIND_CDN_ENABLED=true
Routes
The package registers these routes under route_prefix:
| Method | URI | Name |
|---|---|---|
| GET | / |
home |
| GET | /login |
login |
| POST | /login |
login.store |
| POST | /logout |
logout |
| GET | /dashboard |
dashboard |
| GET | /register |
register |
| POST | /register |
register.store |
| GET | /forgot-password |
password.request |
| POST | /forgot-password |
password.email |
| GET | /reset-password/{token} |
password.reset |
| POST | /reset-password |
password.store |
| GET | /two-factor-challenge |
two-factor.challenge |
| POST | /two-factor-challenge |
two-factor.challenge.store |
| POST | /two-factor-challenge/resend |
two-factor.challenge.resend |
| GET | /verify-email |
verification.notice |
| GET | /verify-email/{id}/{hash} |
verification.verify |
| POST | /email/verification-notification |
verification.send |
| GET | /profile |
profile.edit |
| PATCH | /profile |
profile.update |
| GET | /profile/password |
profile.password |
| PUT | /profile/password |
profile.password.update |
| GET | /settings |
settings.index |
| GET | /settings/security |
settings.security |
| POST | /settings/security/two-factor |
two-factor.enable |
| DELETE | /settings/security/two-factor |
two-factor.disable |
| POST | /settings/security/recovery-codes |
two-factor.recovery-codes.regenerate |
| GET | /settings/devices |
settings.devices |
| DELETE | /settings/devices/{session} |
settings.devices.destroy |
| DELETE | /settings/devices |
settings.devices.destroy-other |
Registration, password reset, and email verification routes can be disabled from config.
Two-factor Flow
After a valid email and password login, users with two-factor enabled are not fully logged in. The package stores a temporary pending two-factor session and redirects to /two-factor-challenge.
If the user selected Authenticator app, the challenge accepts an authenticator OTP or an unused recovery code. If the user selected Email OTP, the package sends a code through SMTP and accepts that OTP or an unused recovery code.
A valid challenge response completes login, regenerates the session, clears the pending two-factor session, and redirects to the configured dashboard.
Recovery codes are single use. When a recovery code is accepted, it is removed from the encrypted recovery code list.
Protecting App Routes
Use Laravel's auth middleware for protected routes. To require two-factor verification for your own routes, add the package middleware alias:
Route::middleware(['auth', 'auth-suite.two_factor'])->group(function () {
Route::get('/dashboard', DashboardController::class);
});
Publishable Assets
Publish config:
php artisan vendor:publish --tag=auth-suite-config
Publish views:
php artisan vendor:publish --tag=auth-suite-views
Publish migrations:
php artisan vendor:publish --tag=auth-suite-migrations
Customizing Views
The installer places editable views in:
resources/views/Auth
resources/views/layouts
resources/views/layouts/partials
Important view groups:
resources/views/Authfor login, register, reset password, email verification, and two-factor challengeresources/views/Auth/Profilefor profile and password pagesresources/views/Auth/Settingsfor settings, security, and devices pagesresources/views/layouts/app.blade.phpfor the main layoutresources/views/layouts/partials/navbar.blade.phpfor the navbar and account dropdownresources/views/layouts/partials/footer.blade.phpfor the footer
The default navbar account dropdown contains only Profile, Settings, and Logout.
Security Notes
- Passwords are hashed with Laravel's
Hashservice. - Login attempts are rate limited by email and IP address.
- Session IDs are regenerated after successful login.
- Sessions are invalidated on logout.
- Users are not fully logged in before passing the two-factor challenge when two-factor is enabled.
- Email OTP codes are stored as hashes in the pending session and expire automatically.
- Email OTP resend is rate limited.
- Device disconnect only removes sessions owned by the authenticated user.
- Disconnecting all other devices requires current-password confirmation.
- Two-factor secrets and recovery codes are encrypted with Laravel
Crypt. - Recovery codes are single use.
Troubleshooting
- If the install command is missing, run
composer dump-autoloadandphp artisan package:discover. - If generated files are not updated, run
php artisan auth:install --force. - If two-factor methods are missing, confirm
HasTwoFactorAuthenticationis added to the User model. - If Email OTP is not delivered, confirm the application's
MAIL_*SMTP values are valid and runphp artisan optimize:clear. - If devices are not listed, set
SESSION_DRIVER=databaseand runphp artisan migrate. - If route changes are not visible, run
php artisan optimize:clear. - If columns already exist, the migrations skip them using
Schema::hasColumnandSchema::hasTable. - If routes conflict with your application, set
AUTH_SUITE_ROUTE_PREFIX=auth.