Skip to main content
The web authentication layer uses Laravel’s session guard with the web driver. All routes are rendered through Inertia, so the browser never receives a traditional full-page redirect from the auth endpoints — the React app handles the UI state.

Guards and session configuration

The web guard is configured in config/auth.php:
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
        'expire' => 120, // minutes
    ],
    'admin' => [
        'driver' => 'session',
        'provider' => 'admins', // Filament admin panel
        'expire' => 60,
    ],
],
The admin guard uses a separate FilamentUser model and is reserved for the Filament admin panel (/admin). Standard tenant users authenticate through the web guard.

Routes

All web auth routes are defined in routes/auth.php and loaded within the / prefix.

Guest-only routes

These routes are wrapped in middleware('guest') — authenticated users are redirected away:
MethodPathNamed routeController action
GET/registerregisterRegisteredUserController@create
POST/registerRegisteredUserController@store
GET/loginloginAuthenticatedSessionController@create
POST/loginAuthenticatedSessionController@store
GET/forgot-passwordpassword.requestPasswordResetLinkController@create
POST/forgot-passwordpassword.emailPasswordResetLinkController@store
GET/reset-password/{token}password.resetNewPasswordController@create
POST/reset-passwordpassword.storeNewPasswordController@store

Authenticated-only routes

These routes require middleware('auth'):
MethodPathNamed routeDescription
GET/verify-emailverification.noticeEmail verification prompt
GET/verify-email/{id}/{hash}verification.verifyVerify email (signed URL, throttle 6/min)
POST/email/verification-notificationverification.sendResend verification email (throttle 6/min)
GET/confirm-passwordpassword.confirmConfirm password prompt
POST/confirm-passwordConfirm password action
PUT/passwordpassword.updateUpdate password
GET/profileprofile.editProfile edit page
PATCH/profileprofile.updateUpdate profile
DELETE/profileprofile.destroyDelete account
POST/logoutlogoutDestroy session

Registration flow

1

Display the form

GET /register renders the Auth/Register Inertia page via RegisteredUserController@create.
2

Submit registration

POST /register is handled by RegisteredUserController@store. The request is validated by RegisterTenantRequest, then a RegisterTenantCommand is dispatched through the command bus.The command creates both the user and the associated tenant in a single atomic operation.
$command = new RegisterTenantCommand(
    businessName: $request->validated('business_name'),
    slug: Str::slug($request->validated('slug')),
    ownerName: $request->validated('name'),
    email: $request->validated('email'),
    password: $request->validated('password'),
    cityId: $cityId,
    categoryId: $categoryId,
    whatsapp: $request->validated('whatsapp'),
    selectedPlan: $request->validated('selected_plan', 'free'),
    idempotencyKey: $request->header('X-Idempotency-Key')
);
3

Auto-login and redirect

After successful registration, the user is logged in immediately and redirected to the Filament dashboard:
$user = User::where('email', $result->ownerEmail)->firstOrFail();
$this->auth->login($user);
return redirect()->route('filament.admin.pages.dashboard');

Login flow

1

Display the form

GET /login renders Auth/Login with canResetPassword and status props.
2

Authenticate

POST /login delegates to LoginRequest::authenticate(). On success, the session is regenerated to prevent session fixation, and the user is redirected to their intended destination.
$request->authenticate();
$request->session()->regenerate();
return redirect()->intended(route('dashboard', absolute: false));
3

Logout

POST /logout invalidates the session and regenerates the CSRF token before redirecting to /.

Email verification

The User model implements MustVerifyEmail. Laravel attaches a signed URL to the verification email. The verification route enforces both the signed middleware (tamper-proof URL) and throttle:6,1 (6 attempts per minute).
Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
    ->middleware(['signed', 'throttle:6,1'])
    ->name('verification.verify');
Email verification is required before a tenant owner can access protected areas. The profile controller checks $request->user() instanceof MustVerifyEmail and surfaces a banner if verification is pending.

Password reset

Password reset tokens are stored in password_reset_tokens and expire after 60 minutes (configurable via AUTH_PASSWORD_TIMEOUT). A new token cannot be requested more than once per minute ('throttle' => 60).

Profile management

The ProfileController delegates to two application-layer actions:
  • UpdateUserProfileAction — handles dirty email detection and saves changes.
  • DeleteUserAction — requires current password confirmation before deleting the account and invalidating the session.
public function destroy(Request $request): RedirectResponse
{
    $request->validate(['password' => ['required', 'current_password']]);
    $user = $request->user();
    $this->auth->logout();
    $this->deleteUserAction->execute($user);
    $request->session()->invalidate();
    $request->session()->regenerateToken();
    return $this->redirector->to('/');
}

Build docs developers (and LLMs) love