Problem implementing stancl/tenancy with Filament 4

I’ve been trying for days but I can’t get multitenancy to work. I’ve installed Stancl, and I’m at the point where I can create tenants from the backend with a dedicated database and admin user. But I have a login issue: If I visit a URL like tenant1.mysite.ddev.site/login or tenant2.mysite.ddev.site (these are two existing tenants), I see the login screen, but when I try to log in I get: “This page has expired. Would you like to refresh the page?” Also, if I visit tenant3.mysite.ddev.site (this tenant doesn’t exist), I still see the login screen! The admin panel login at mysite.ddev.site/admin works fine. But if I visit tenant1.mysite.ddev.site/admin it lets me log in to the admin panel (!!), even if I visit tenant3.mysite.ddev.site/admin (which doesn’t exist)...
2 Replies
Soundmit
SoundmitOP3mo ago
TenantPanelProvider.php
<?php

namespace App\Providers\Filament;

use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Pages\Dashboard;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Widgets\AccountWidget;
use Filament\Widgets\FilamentInfoWidget;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
use App\Models\Tenant;

class TenantPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->id('tenant')
->path('')
->login()
->colors([
'primary' => Color::Blue,
])
->tenant(Tenant::class, 'domain')
->tenantDomain('{tenant:domain}.'.config('app.domain'))

->discoverResources(in: app_path('Filament/Tenant/Resources'), for: 'App\Filament\Tenant\Resources')
->discoverPages(in: app_path('Filament/Tenant/Pages'), for: 'App\Filament\Tenant\Pages')
->pages([
Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Tenant/Widgets'), for: 'App\Filament\Tenant\Widgets')
->widgets([
AccountWidget::class,
FilamentInfoWidget::class,
])

->viteTheme('resources/css/filament/tenant/theme.css')
->authMiddleware([
Authenticate::class,
]);
}
}
<?php

namespace App\Providers\Filament;

use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Pages\Dashboard;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Widgets\AccountWidget;
use Filament\Widgets\FilamentInfoWidget;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
use App\Models\Tenant;

class TenantPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->id('tenant')
->path('')
->login()
->colors([
'primary' => Color::Blue,
])
->tenant(Tenant::class, 'domain')
->tenantDomain('{tenant:domain}.'.config('app.domain'))

->discoverResources(in: app_path('Filament/Tenant/Resources'), for: 'App\Filament\Tenant\Resources')
->discoverPages(in: app_path('Filament/Tenant/Pages'), for: 'App\Filament\Tenant\Pages')
->pages([
Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Tenant/Widgets'), for: 'App\Filament\Tenant\Widgets')
->widgets([
AccountWidget::class,
FilamentInfoWidget::class,
])

->viteTheme('resources/css/filament/tenant/theme.css')
->authMiddleware([
Authenticate::class,
]);
}
}
route/tenant.php
<?php

declare(strict_types=1);

use Illuminate\Support\Facades\Route;
use Stancl\Tenancy\Middleware\InitializeTenancyBySubdomain;
use Stancl\Tenancy\Middleware\PreventAccessFromCentralDomains;
use Stancl\Tenancy\Middleware\AbortIfTenantDoesNotExist;
use Stancl\Tenancy\Features\UserImpersonation;

/*
|--------------------------------------------------------------------------
| Tenant Routes
|--------------------------------------------------------------------------
|
| Here you can register the tenant routes for your application.
| These routes are loaded by the TenantRouteServiceProvider.
|
| Feel free to customize them however you want. Good luck!
|
*/

Route::middleware([
'web',
InitializeTenancyBySubdomain::class,
PreventAccessFromCentralDomains::class,
AbortIfTenantDoesNotExist::class,
])->group(function () {
Route::get('/', function () {
return 'Ciao, This is your multi-tenant application. The id of the current tenant is ' . tenant('id');
});

});

Route::get('/impersonate/{token}', function ($token) {
return UserImpersonation::makeResponse($token);
});
<?php

declare(strict_types=1);

use Illuminate\Support\Facades\Route;
use Stancl\Tenancy\Middleware\InitializeTenancyBySubdomain;
use Stancl\Tenancy\Middleware\PreventAccessFromCentralDomains;
use Stancl\Tenancy\Middleware\AbortIfTenantDoesNotExist;
use Stancl\Tenancy\Features\UserImpersonation;

/*
|--------------------------------------------------------------------------
| Tenant Routes
|--------------------------------------------------------------------------
|
| Here you can register the tenant routes for your application.
| These routes are loaded by the TenantRouteServiceProvider.
|
| Feel free to customize them however you want. Good luck!
|
*/

Route::middleware([
'web',
InitializeTenancyBySubdomain::class,
PreventAccessFromCentralDomains::class,
AbortIfTenantDoesNotExist::class,
])->group(function () {
Route::get('/', function () {
return 'Ciao, This is your multi-tenant application. The id of the current tenant is ' . tenant('id');
});

});

Route::get('/impersonate/{token}', function ($token) {
return UserImpersonation::makeResponse($token);
});
bootstrap/providers.php
<?php

return [
App\Providers\AppServiceProvider::class,
App\Providers\Filament\AdminPanelProvider::class,
App\Providers\Filament\TenantPanelProvider::class,
App\Providers\TenancyServiceProvider::class,
];
<?php

return [
App\Providers\AppServiceProvider::class,
App\Providers\Filament\AdminPanelProvider::class,
App\Providers\Filament\TenantPanelProvider::class,
App\Providers\TenancyServiceProvider::class,
];
Dan Harrin
Dan Harrin3mo ago
I have never used stancl/tenancy, but I use spatie/multitenancy without any issues very often

Did you find this page helpful?