Looking to hire Laravel developers? Try LaraJobs

laravel-auth-suite maintained by mwy

Description
Blade authentication package with two-factor authentication and device management for Laravel.
Last update
2026/05/29 18:19 (dev-master)
License
Links
Downloads
0

Comments
comments powered by Disqus

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 users table with name, email, and password

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
  • --force overwrites generated package files in the application.
  • --skip-app-files publishes 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/Auth for login, register, reset password, email verification, and two-factor challenge
  • resources/views/Auth/Profile for profile and password pages
  • resources/views/Auth/Settings for settings, security, and devices pages
  • resources/views/layouts/app.blade.php for the main layout
  • resources/views/layouts/partials/navbar.blade.php for the navbar and account dropdown
  • resources/views/layouts/partials/footer.blade.php for the footer

The default navbar account dropdown contains only Profile, Settings, and Logout.

Security Notes

  • Passwords are hashed with Laravel's Hash service.
  • 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-autoload and php artisan package:discover.
  • If generated files are not updated, run php artisan auth:install --force.
  • If two-factor methods are missing, confirm HasTwoFactorAuthentication is added to the User model.
  • If Email OTP is not delivered, confirm the application's MAIL_* SMTP values are valid and run php artisan optimize:clear.
  • If devices are not listed, set SESSION_DRIVER=database and run php artisan migrate.
  • If route changes are not visible, run php artisan optimize:clear.
  • If columns already exist, the migrations skip them using Schema::hasColumn and Schema::hasTable.
  • If routes conflict with your application, set AUTH_SUITE_ROUTE_PREFIX=auth.