Tenant Routes

Routes within routes/tenant.php will have the web and tenancy middleware groups automatically applied on them.

Just like routes/web.php, these routes use the App\Http\Controllers namespace (you can configure this)

If a tenant cannot be identified, an exception will be thrown. If you want to change this behavior (to a redirect, for example) read the Middleware Configuration page.

Middleware

The package automatically adds the InitializeTenancy middleware to the global middleware stack. This middleware checks if the current domain is not part of tenancy.exempt_domains. If not, it attempts to identify the tenant based on the current hostname. Once the tenant is identified, the database connection, cache, filesystem root paths and, optionally, Redis connection, will be switched.

After the global middleware is executed, the controllers are constructed.

After that, the route middleware is executed.

All route groups in your application should have the \Stancl\Tenancy\Middleware\PreventAccessFromTenantDomains middleware applied on them, to prevent access from tenant domains to central routes and vice versa. See below for more detail about the PreventAccessFromTenantDomains middleware.

All tenant routes in your application should have the tenancy middleware group applied on them.

The tenancy middleware group marks the route as a tenant route. That middleware functions as a "flag" for the PreventAccessFromTenantDomains, telling it that the route is a tenant route, since the middleware has no other way of distingushing central from tenant routes.

In previous versions, the InitializeTenancy middleware was applied only on tenant routes. However, that lead to tenancy not being initialized in controller constructors, which could cause bugs. So from 2.1.0 on, tenancy is initialized on all routes on non-exempt domains, and if the route is not tenant, the request gets aborted by the PreventAccessFromTenantDomains once Laravel reaches the route middleware step.

Central routes

Routes in files other than routes/tenant.php will not have the tenancy middleware automatically applied on them, so they will be central routes. If you want these routes to be tenant routes, you can apply the tenancy middleware manually, as described in custom route groups below.

API routes / custom route groups

If you want certain routes (perhaps API routes) to be multi-tenant, wrap them in a Route group with this middleware:

Route::middleware('tenancy')->group(function () {
    // Route::get('/', 'HelloWorld');
});

and make sure the Stancl\Tenancy\Middleware\PreventAccessFromTenantDomains middleware is applied on the entire group:

// app/Http/Kernel.php
protected $middlewareGroups = [
    // ...
    'api' => [
        \Stancl\Tenancy\Middleware\PreventAccessFromTenantDomains::class,
        // ...
    ]
];

The PreventAccess... middleware

The Stancl\Tenancy\Middleware\PreventAccessFromTenantDomains middleware prevents access to non-tenant routes from tenant domains by returning a redirect to the tenant app's home page (tenancy.home_url). Conversely, it returns a 404 when a user attempts to visit a tenant route on a web (exempt) domain.

The tenancy:install command applies this middleware to the web and api groups. To apply it for another route group, add this middleware manually to that group. You can do this in app/Http/Kernel.php.

Conflicting routes

By default, you cannot have conflicting routes in web.php and tenant.php. It would break php artisan route:list and route caching.

However, tenant routes are loaded after the web/api routes, so if you register your central routes only for domains listed in the tenancy.exempt_domains config, you can use the same URLs for central and tenant routes.

Here's an example implementation:

// RouteServiceProvider

protected function mapWebRoutes()
{
    foreach (config('tenancy.exempt_domains', []) as $domain) {
        Route::middleware('web')
            ->domain($domain)
            ->namespace($this->namespace)
            ->group(base_path('routes/web.php'));
    }
}

protected function mapApiRoutes()
{
    foreach (config('tenancy.exempt_domains', []) as $domain) {
        Route::prefix('api')
            ->middleware('api')
            ->domain($domain)
            ->namespace($this->namespace)
            ->group(base_path('routes/api.php'));
    }
}

One thing to keep in mind though: If you use multiple exempt domains, you cannot use route names. They can be used only once, so the name would link to the URL on the first exempt domain.

If you don't need conflicting routes, you may want to do the following: Since you probably want cleaner URLs on your non-tenant part of the application (landing page, etc), prefix your tenant routes with something like /app.