Skip to content

Middleware ​

Overview ​

Middleware intercepts HTTP requests before they reach controllers and responses before they're sent to clients.

text
Request
  ↓
Middleware 1 (before)
  ↓
Middleware 2 (before)
  ↓
Controller
  ↓
Middleware 2 (after)
  ↓
Middleware 1 (after)
  ↓
Response

Global Middleware ​

Applied to all routes:

php
use Nexphant\App;
use Nexphant\Server\Middleware\{Cors, Logger, Security};

$app = App::create();

$app->middleware(Cors::class);
$app->middleware(Logger::class);
$app->middleware(Security::class);

Route Middleware ​

Applied to specific routes:

php
$app->get('/admin', function () {
    return ['admin' => 'panel'];
})->middleware('auth');

Middleware Aliases ​

Define reusable aliases:

php
$app->middlewareAlias([
    'auth' => \Nexphant\Server\Middleware\AuthMiddleware::class,
    'jwt' => \Nexphant\Server\Middleware\JwtMiddleware::class,
    'csrf' => \Nexphant\Server\Middleware\CsrfMiddleware::class,
    'throttle' => \Nexphant\Server\Middleware\RateLimit::class,
]);

// Usage
$app->get('/api/data', fn() => [])->middleware('auth');

Route Groups ​

php
$app->group(['middleware' => ['auth', 'csrf']], function ($group) {
    $group->get('/profile', fn() => ['user' => auth()->user()]);
    $group->post('/update', fn(Request $req) => ['updated' => true]);
});

Built-in Middleware ​

CORS ​

Cross-Origin Resource Sharing:

php
use Nexphant\Server\Middleware\Cors;

$cors = new Cors([
    'origins' => ['https://example.com'],
    'methods' => ['GET', 'POST', 'PUT', 'DELETE'],
    'headers' => ['Content-Type', 'Authorization'],
    'credentials' => true,
    'max_age' => 3600,
]);

$app->middleware($cors);

Allow all:

php
$cors = new Cors([
    'origins' => ['*'],
    'methods' => ['*'],
    'headers' => ['*'],
]);

Rate Limiting ​

php
use Nexphant\Server\Middleware\RateLimit;

$rateLimit = new RateLimit(
    attempts: 60,  // requests
    per: 1,        // minutes
);

$app->get('/api/data', fn() => [])
    ->middleware($rateLimit);

Attribute-based:

php
use Nexphant\Server\Attributes\Throttle;

class ApiController
{
    #[Throttle(attempts: 60, per: 1)]
    public function index()
    {
        return ['data' => []];
    }
}

Security Headers ​

php
use Nexphant\Server\Middleware\Security;

$security = new Security([
    'csp' => "default-src 'self'",
    'xss_protection' => true,
    'content_type_nosniff' => true,
    'frame_options' => 'SAMEORIGIN',
    'hsts' => [
        'enabled' => true,
        'max_age' => 31536000,
        'include_subdomains' => true,
    ],
]);

$app->middleware($security);

Compression ​

php
use Nexphant\Server\Middleware\Compress;

$compress = new Compress([
    'threshold' => 1024, // Compress responses > 1KB
    'level' => 6,        // Compression level (1-9)
]);

$app->middleware($compress);

Request Timeout ​

php
use Nexphant\Server\Middleware\Timeout;

$timeout = new Timeout(seconds: 30);

$app->middleware($timeout);

Logger ​

php
use Nexphant\Server\Middleware\Logger;

$logger = new Logger([
    'format' => ':method :url :status :response_time ms',
    'skip' => ['/health', '/metrics'],
]);

$app->middleware($logger);

Session ​

php
use Nexphant\Server\Middleware\SessionMiddleware;

$app->middleware(SessionMiddleware::class);

CSRF Protection ​

php
use Nexphant\Server\Middleware\CsrfMiddleware;

$app->middleware(SessionMiddleware::class);
$app->middleware(CsrfMiddleware::class);

Authentication ​

php
use Nexphant\Server\Middleware\AuthMiddleware;

$app->middlewareAlias(['auth' => AuthMiddleware::class]);

$app->get('/profile', fn() => [])->middleware('auth');

JWT ​

php
use Nexphant\Server\Middleware\JwtMiddleware;

$jwt = new JwtMiddleware([
    'secret' => env('JWT_SECRET'),
    'algorithm' => 'HS256',
]);

$app->middlewareAlias(['jwt' => $jwt]);

$app->get('/api/protected', fn() => [])->middleware('jwt');
php
use Nexphant\Server\Middleware\CookieMiddleware;

$app->middleware(CookieMiddleware::class);

Trusted Proxy ​

php
use Nexphant\Server\Middleware\TrustedProxyMiddleware;

$proxy = new TrustedProxyMiddleware([
    'proxies' => ['10.0.0.0/8', '172.16.0.0/12'],
    'headers' => [
        'forwarded' => 'X-Forwarded-For',
        'proto' => 'X-Forwarded-Proto',
        'host' => 'X-Forwarded-Host',
        'port' => 'X-Forwarded-Port',
    ],
]);

$app->middleware($proxy);

Content Security Policy ​

php
use Nexphant\Server\Middleware\CspMiddleware;

$csp = new CspMiddleware([
    'default-src' => ["'self'"],
    'script-src' => ["'self'", "'unsafe-inline'", 'https://cdn.example.com'],
    'style-src' => ["'self'", "'unsafe-inline'"],
    'img-src' => ["'self'", 'data:', 'https:'],
    'font-src' => ["'self'", 'data:'],
    'report-uri' => '/csp-report',
]);

$app->middleware($csp);

Metrics ​

php
use Nexphant\Server\Middleware\MetricsMiddleware;

$metrics = new MetricsMiddleware();

$app->middleware($metrics);

Custom Middleware ​

Basic Structure ​

php
use Nexphant\Server\Middleware\MiddlewareInterface;

class CustomMiddleware implements MiddlewareInterface
{
    public function handle($request, $next)
    {
        // Before controller
        
        $response = $next($request);
        
        // After controller
        
        return $response;
    }
}

Modify Request ​

php
class AddHeaderMiddleware implements MiddlewareInterface
{
    public function handle($request, $next)
    {
        $request = $request->withHeader('X-Custom', 'value');
        
        return $next($request);
    }
}

Modify Response ​

php
class AddResponseHeaderMiddleware implements MiddlewareInterface
{
    public function handle($request, $next)
    {
        $response = $next($request);
        
        return $response->withHeader('X-Response-Time', '100ms');
    }
}

Early Return ​

php
class MaintenanceModeMiddleware implements MiddlewareInterface
{
    public function handle($request, $next)
    {
        if (file_exists(storage_path('maintenance.lock'))) {
            return Response::json([
                'error' => 'Site under maintenance',
            ])->withStatus(503);
        }
        
        return $next($request);
    }
}

With Configuration ​

php
class IpWhitelistMiddleware implements MiddlewareInterface
{
    private array $whitelist;
    
    public function __construct(array $whitelist)
    {
        $this->whitelist = $whitelist;
    }
    
    public function handle($request, $next)
    {
        $ip = $request->ip();
        
        if (!in_array($ip, $this->whitelist)) {
            return Response::json(['error' => 'Forbidden'])
                ->withStatus(403);
        }
        
        return $next($request);
    }
}

// Usage
$app->middleware(new IpWhitelistMiddleware([
    '192.168.1.1',
    '10.0.0.1',
]));

Complete Examples ​

API with Auth + Rate Limiting ​

php
use Nexphant\App;
use Nexphant\Server\Middleware\{JwtMiddleware, RateLimit, Cors};

$app = App::create();

// Global
$app->middleware(new Cors(['origins' => ['*']]));

// Aliases
$app->middlewareAlias([
    'jwt' => new JwtMiddleware(['secret' => env('JWT_SECRET')]),
    'throttle' => new RateLimit(60, 1),
]);

// Public routes
$app->post('/auth/login', fn(Request $req) => ['token' => 'jwt...']);

// Protected routes
$app->group(['prefix' => '/api', 'middleware' => ['jwt', 'throttle']], function ($group) {
    $group->get('/users', fn() => User::query()->get());
    $group->post('/users', fn(Request $req) => ['created' => true]);
});

$app->listen(port: 8080);

Admin Panel ​

php
$app->middlewareAlias([
    'auth' => AuthMiddleware::class,
    'admin' => AdminMiddleware::class,
    'csrf' => CsrfMiddleware::class,
]);

$app->group(['prefix' => '/admin', 'middleware' => ['auth', 'admin', 'csrf']], function ($group) {
    $group->get('/dashboard', fn() => view('admin.dashboard'));
    $group->get('/users', fn() => view('admin.users'));
    $group->post('/users', fn(Request $req) => ['created' => true]);
});

Multi-tenant Application ​

php
class TenantMiddleware implements MiddlewareInterface
{
    public function handle($request, $next)
    {
        $subdomain = $request->subdomain();
        
        $tenant = Tenant::query()
            ->where('subdomain', $subdomain)
            ->first();
        
        if (!$tenant) {
            return Response::json(['error' => 'Tenant not found'])
                ->withStatus(404);
        }
        
        // Store tenant in context
        Context::set('tenant', $tenant);
        
        // Switch database connection
        DB::setConnection($tenant->database);
        
        return $next($request);
    }
}

$app->middleware(new TenantMiddleware());

Middleware Order ​

Order matters:

php
// Correct order
$app->middleware(TrustedProxyMiddleware::class);  // 1. Trust proxy
$app->middleware(Cors::class);                     // 2. CORS
$app->middleware(SessionMiddleware::class);        // 3. Session
$app->middleware(CsrfMiddleware::class);          // 4. CSRF
$app->middleware(AuthMiddleware::class);          // 5. Auth
$app->middleware(RateLimit::class);               // 6. Rate limit

Conditional Middleware ​

php
class ConditionalMiddleware implements MiddlewareInterface
{
    public function handle($request, $next)
    {
        if ($request->is('/api/*')) {
            // API logic
        } else {
            // Web logic
        }
        
        return $next($request);
    }
}

Best Practices ​

  1. Order middleware correctly (proxy → cors → session → csrf → auth)
  2. Use global middleware for cross-cutting concerns
  3. Use route middleware for specific routes
  4. Keep middleware focused on single responsibility
  5. Return early when possible
  6. Use aliases for reusability
  7. Configure middleware via constructor
  8. Test middleware independently

Next Steps ​

Released under the MIT License.