Auth & Middleware
Last updated: 04/17/2026 · Written by Agent0
Auth & Middleware
StackCTL includes a built-in authentication system and a set of route middleware that handles the most common access control scenarios out of the box. Middleware is applied directly in your route definitions — no separate configuration files needed.
Built-in Middleware
The following middleware is registered automatically and is available on any route without any setup.
auth — Require login
Redirects unauthenticated users to /login. Use this on any route that requires the user to be signed in.
$router->get('/dashboard', 'DashboardController@index')
->middleware('auth');
guest — Require no login
Redirects already-authenticated users to /dashboard. Use this on login and registration pages so logged-in users don't see them.
$router->get('/login', 'AuthController@login')
->middleware('guest');
role — Require a specific role
Checks that the authenticated user's role matches. Aborts with a 403 Forbidden if it doesn't. Pass multiple roles separated by commas — the user must have any one of them.
// Single role
$router->get('/admin', 'AdminController@index')
->middleware('role:admin');
// Any of multiple roles
$router->get('/reports', 'ReportsController@index')
->middleware('role:admin,developer,editor');
can — Require a permission
Checks the user against the permissions map defined in config/auth.php. Aborts with 403 if the check fails. Takes an action and a resource as parameters.
$router->get('/articles/approve/{id}', 'ArticlesController@approve')
->middleware('can:approve,article');
Define the permission map in config/auth.php:
'permissions' => [
'edit' => ['article' => ['admin', 'editor']],
'approve' => ['article' => ['admin']],
'delete' => ['article' => ['admin']],
],
Route Groups
Apply middleware to multiple routes at once by wrapping them in a group. All routes inside the group inherit the group's middleware — no need to repeat it on every route.
// All routes in this group require login
$router->group(['middleware' => 'auth'], function ($router) {
$router->get('/dashboard', 'DashboardController@index');
$router->get('/profile', 'ProfileController@index');
$router->post('/profile', 'ProfileController@update');
});
// Prefix + middleware together
$router->group(['prefix' => '/admin', 'middleware' => 'role:admin'], function ($router) {
$router->get('/users', 'AdminController@users'); // → /admin/users
$router->get('/settings', 'AdminController@settings'); // → /admin/settings
});
Nested groups
Groups can be nested. Middleware stacks from the outside in — both layers apply to the innermost routes.
$router->group(['middleware' => 'auth'], function ($router) {
$router->group(['middleware' => 'role:admin'], function ($router) {
$router->get('/admin', 'AdminController@index');
// Requires: logged in AND role is admin
});
});
Custom Middleware
For anything project-specific, use $router->define() to register a custom middleware by name. Define it once in routes/web.php and use it just like the built-ins.
// Define the middleware
$router->define('subscribed', function () {
if (!user('is_subscribed')) {
redirect('/upgrade');
}
});
// Apply it to routes
$router->get('/premium', 'PremiumController@index')
->middleware('subscribed');
Auth Helpers
Beyond route protection, StackCTL provides a set of global helpers for checking auth state anywhere in your controllers or views.
is_auth()
Returns true if the current user is logged in.
if (is_auth()) {
// user is logged in
}
auth()
Returns the current user's session data. Pass a field name to get a specific value.
auth() // full session array
auth('name') // display name
auth('email') // email address
auth('role') // role string
user()
Returns the current user's full database record. Only runs one query per request regardless of how many times it's called — the result is cached statically.
user() // full database record
user('email') // specific field
user('is_subscribed') // any column from the users table
Use auth() for quick access to session-stored values (name, email, role). Use user() when you need accurate, up-to-date data directly from the database.
has_role()
Check if the current user has a specific role. Pass a string for one role or an array to check if the user has any of the listed roles.
has_role('admin')
has_role(['admin', 'developer'])
can()
Check a permission directly in a controller or view — the same check the can: middleware runs.
if (can('edit', 'article')) {
// show edit button
}
// In a view:
<?php if (can('delete', 'article')): ?>
<button>Delete</button>
<?php endif; ?>
Auth Configuration
The authentication system has several options you can toggle in config/auth.php:
- allow_registration — Enable or disable public user registration
- verify_email — Require email verification after registration
- remember_me — Enable "Remember Me" persistent login via a secure cookie
- mfa_enabled — Enable multi-factor authentication (email code or authenticator app)
- permissions — Define the action/resource/role map used by
can()andcan:middleware