Core Concepts
Middleware
Middleware provides a convenient mechanism for inspecting and filtering HTTP requests entering your application.
What is Middleware?
Kipchak is built on the Slim Framework, which uses PSR-15 middleware. Middleware acts as a layer between the client request and your route handler, allowing you to:
- Authenticate and authorize requests
- Log request/response data
- Add security headers
- Rate limit requests
- Parse and validate input
- Transform responses
Middleware executes in a chain, with each piece of middleware deciding whether to pass the request to the next middleware or return early.
How Middleware Works
Middleware executes in LIFO (Last In, First Out) order:
$app->add(new ThirdMiddleware()); // Executes third
$app->add(new SecondMiddleware()); // Executes second
$app->add(new FirstMiddleware()); // Executes first
Request flow: FirstMiddleware → SecondMiddleware → ThirdMiddleware → RouteHandler Response flow: RouteHandler → ThirdMiddleware → SecondMiddleware → FirstMiddleware
Applying Middleware
Global Middleware
Apply middleware to all routes by registering it in middlewares/middlewares.php:
Middlewares written for Kipchak must adhere to the middleware interface and implement the initialise method.
<?php
use Kipchak\Middleware\Subashi\Subashi;
use Kipchak\Middleware\Error\Error;
use Kipchak\Middleware\Auth\Key\Key;
use Kipchak\Middleware\Auth\JWKS\JWKS;
use Slim\App;
/**
* @var App $app
*/
Error::initialise($app); // Error handling
Key::initialise($app); // API key authentication
JWKS::initialise($app); // JWKS authentication
Subashi::initialise($app); // WAF
Middleware added here applies to every request.
Route Group Middleware
Apply middleware to specific route groups:
<?php
use Api\Controllers;
use Kipchak\Middleware\Auth\JWKS\Handlers\AuthJWKS;
use Slim\Routing\RouteCollectorProxy;
$app->group('/v1', function(RouteCollectorProxy $group) {
$group->get('/protected',
[
Controllers\v1\Protected::class,
'get'
]
);
})->add(new AuthJWKS($app->getContainer(), ['email']));
This middleware only applies to routes within the /v1 group.
Single Route Middleware
Apply middleware to individual routes:
$app->get('/admin', [Controllers\Admin::class, 'dashboard'])
->add(new AdminAuthMiddleware());
Built-in Middleware
Error Middleware
Handles exceptions and errors, providing structured error responses:
use Kipchak\Middleware\Error\Error;
Error::initialise($app);
Configured via kipchak.api.php:
return [
'logExceptions' => true,
'logExceptionDetails' => true,
];
API Key Authentication
Validates API keys via headers or query parameters:
use Kipchak\Middleware\Auth\Key\Key;
use Kipchak\Middleware\Auth\Key\Handlers\ApiKey;
// Global
Key::initialise($app);
// Specific routes
$app->group('/v1', function($group) {
// Routes here
})->add(new ApiKey($app->getContainer()));
Configuration in kipchak.auth.key.php:
return [
'enabled' => false,
'ignore_options' => true,
'ignore_paths' => ['/status'],
'authorised_keys' => [
'key1' => 'client1',
'key2' => 'client2',
],
'header' => 'apikey',
'query_param' => 'apikey'
];
API keys can be provided as:
- Header:
X-API-Key: key1or custom header - Query parameter:
?apikey=key1
JWKS Authentication
Validates JSON Web Tokens using JSON Web Key Sets:
use Kipchak\Middleware\Auth\JWKS\JWKS;
use Kipchak\Middleware\Auth\JWKS\Handlers\AuthJWKS;
// Global
JWKS::initialise($app);
// Specific routes with custom scopes
$app->group('/v1', function($group) {
// Routes here
})->add(new AuthJWKS($app->getContainer(), ['email', 'profile']));
Configuration in kipchak.auth.jwks.php:
return [
'enabled' => false,
'ignore_options' => true,
'ignore_paths' => ['/status'],
'jwksUri' => 'https://auth.example.com/certs',
'validate_scopes' => true,
'scopes' => ['email', 'profile'],
];
The middleware:
- Validates JWT signature using JWKS
- Checks token expiration
- Validates required scopes
- Stores decoded token in container:
$this->container->get('token')
Subashi WAF
Web Application Firewall with IP filtering, rate limiting, and request blocking:
use Kipchak\Middleware\Subashi\Subashi;
Subashi::initialise($app);
Configuration in kipchak.subashi.php supports:
Whitelisting:
'whitelist' => [
[
'name' => 'Whitelist trusted IPs',
'conditions' => [
[
'type' => 'ip',
'operator' => 'in_list',
'values' => ['127.0.0.1', '::1'],
],
],
'action' => 'allow',
],
],
Blacklisting:
'blacklist' => [
[
'name' => 'Block bots',
'conditions' => [
[
'type' => 'header',
'key' => 'User-Agent',
'operator' => 'regex',
'value' => '/(bot|crawler|scraper)/i',
],
],
'action' => 'block',
],
],
Rate Limiting:
'rate_limiting' => [
'enabled' => true,
'default_limit' => 100,
'default_window' => 60,
'store' => 'memcached',
],
'rate_limit_rules' => [
[
'name' => 'Per IP rate limit',
'conditions' => [],
'rate_limit' => [
'limit' => 100,
'window' => 60,
'key_prefix' => 'ip',
'key_source' => 'ip',
],
],
[
'name' => 'Per API key rate limit',
'conditions' => [
[
'type' => 'header',
'key' => 'apikey',
'operator' => 'exists',
],
],
'rate_limit' => [
'limit' => 1000,
'window' => 60,
'key_prefix' => 'apikey',
'key_source' => 'header:apikey',
],
],
],
Creating Custom Middleware
Create custom middleware by implementing PSR-15's MiddlewareInterface:
<?php
namespace Api\Middlewares;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class CustomMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
// Before route handler
// Modify request, check conditions, etc.
$request = $request->withAttribute('custom_data', 'value');
// Call next middleware/handler
$response = $handler->handle($request);
// After route handler
// Modify response, add headers, etc.
$response = $response->withHeader('X-Custom-Header', 'value');
return $response;
}
}
Middleware with Dependencies
Use the container for dependency injection:
<?php
namespace Api\Middlewares;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class AuthMiddleware implements MiddlewareInterface
{
private ContainerInterface $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$logger = $this->container->get('logger');
$config = $this->container->get('config');
// Your middleware logic
return $handler->handle($request);
}
}
Apply it:
$app->group('/v1', function($group) {
// Routes
})->add(new AuthMiddleware($app->getContainer()));
Middleware Execution Order
Understanding execution order is crucial:
// In middlewares/middlewares.php
Error::initialise($app); // 4th in, 1st out
Key::initialise($app); // 3rd in, 2nd out
JWKS::initialise($app); // 2nd in, 3rd out
Subashi::initialise($app); // 1st in, 4th out
// On a route
$app->get('/test', $handler)
->add(new CacheMiddleware()) // 5th in, 5th out (runs after globals)
->add(new LogMiddleware()); // 6th in, 6th out
Request: Log → Cache → Subashi → JWKS → Key → Error → Handler Response: Handler → Error → Key → JWKS → Subashi → Cache → Log
Best Practices
- Order matters - Add middleware in logical order (authentication before authorization)
- Keep middleware focused - Each middleware should do one thing well
- Use global middleware sparingly - Only for truly global concerns (error handling, logging)
- Leverage route groups - Apply middleware to groups of related routes
- Handle errors gracefully - Always consider failure cases
- Use the container - Access shared services via dependency injection
- Document behavior - Clearly document what each middleware does
- Test thoroughly - Middleware affects all requests, test edge cases
Available Middleware Packages
Browse available middleware at https://1x.ax/mamluk/kipchak/middlewares
Popular middleware includes:
- Error - Exception and error handling
- Subashi - WAF with rate limiting and IP filtering
- Auth (JWKS) - JWT authentication via JWKS
- Auth (Key) - API key authentication
- CORS - Cross-Origin Resource Sharing
- JSON - JSON request/response handling