laravel-api-middleware maintained by aporat
Laravel API Middleware
A Laravel package providing middleware for API enhancement, including trust proxies, no-cache enforcement, and SSL requirement validation.
A Laravel package offering middleware to enhance API security and performance with trust proxies, cache prevention, and SSL enforcement.
Requirements
- PHP: 8.4, 8.5
- Laravel: 13.x
Installation
Install the package via Composer:
composer require aporat/laravel-api-middleware
The service provider (ApiMiddlewareServiceProvider) is automatically registered via Laravel's package discovery. If auto-discovery is disabled, add it to config/app.php:
'providers' => [
// ...
Aporat\Laravel\ApiMiddleware\ApiMiddlewareServiceProvider::class,
],
Publish the configuration file:
php artisan vendor:publish --provider="Aporat\Laravel\ApiMiddleware\ApiMiddlewareServiceProvider" --tag="api-middleware-config"
This copies api-middleware.php to your config/ directory.
Configuration
Edit config/api-middleware.php to customize the middleware settings:
<?php
return [
'trust_proxies' => [
// IPs/CIDRs, a comma separated string, "REMOTE_ADDR", or "*" for any proxy.
'proxies' => ['127.0.0.1', '10.0.0.0/8'],
// A Request::HEADER_* bitmask, a named set, or a list of names.
'headers' => 'x_forwarded_aws_elb',
],
'no_cache' => [
'cache_control' => 'no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0',
'pragma' => 'no-cache',
'expires' => '0',
],
'ssl_required' => [
// Path patterns for Request::is() — leading slash optional, "*" supported.
'except_routes' => ['ping'],
'except_environments' => ['local', 'development', 'testing'],
'status' => 403,
],
];
trust_proxies: Trusted proxy IPs/CIDRs and whichX-Forwarded-*headers to honour.headersaccepts a rawSymfony\Component\HttpFoundation\Request::HEADER_*bitmask, one of the named sets below, or a list of names that are OR'd together:forwarded,x_forwarded_for,x_forwarded_host,x_forwarded_proto,x_forwarded_port,x_forwarded_prefix,x_forwarded_aws_elb(the default),x_forwarded_traefik.no_cache:Cache-Control,PragmaandExpiresvalues. Setting any of them tonullomits the header and strips one set upstream. Symfony normalisesCache-Control— directives come back alphabetised withprivateappended unlesspublic/s-maxageis present — so the emitted header will not match the configured string character for character.ssl_required: Exempt path patterns / environments, and the HTTP status used for rejections.
Usage
Middleware
Apply the middleware to routes using their aliases:
// routes/api.php
Route::middleware(['trust.proxies', 'no.cache', 'ssl.required'])->get('/test', function () {
return response()->json(['message' => 'API Enhanced!']);
});
trust.proxies: Trusts the configured proxies soX-Forwarded-*headers are honoured when resolving the client IP, scheme and port.no.cache: Prevents caching of API responses.ssl.required: Rejects plain-HTTP requests with anSslRequiredException(a SymfonyHttpException), except on exempt paths/environments.
Ordering with Laravel's own TrustProxies
Laravel 13 always includes Illuminate\Http\Middleware\TrustProxies in the global stack, and it
resets the trusted set on every request. Register this package's TrustProxies as a
replacement rather than appending it, so it runs in the right slot instead of racing the built-in:
// bootstrap/app.php
use Aporat\Laravel\ApiMiddleware\NoCache;
use Aporat\Laravel\ApiMiddleware\TrustProxies;
->withMiddleware(function (Middleware $middleware) {
$middleware->replace(\Illuminate\Http\Middleware\TrustProxies::class, TrustProxies::class);
$middleware->append(NoCache::class);
})
ssl.required must run after trust.proxies, otherwise every request behind a TLS-terminating
load balancer looks insecure.
Error handling
SslRequiredException extends Symfony\Component\HttpKernel\Exception\HttpException and
deliberately does not define a render() method — Laravel gives an exception's own render()
precedence over the application's Exceptions::render() callbacks, so defining one would force the
package's error shape onto the host app. Format it however your app formats HTTP errors:
->withExceptions(function (Exceptions $exceptions) {
$exceptions->render(function (HttpException $e) {
return new JsonResponse([
'error_code' => $e->getStatusCode(),
'error_message' => $e->getMessage(),
], $e->getStatusCode());
});
})
Manual Instantiation
use Aporat\Laravel\ApiMiddleware\NoCache;
use Aporat\Laravel\ApiMiddleware\SSLRequired;
use Aporat\Laravel\ApiMiddleware\TrustProxies;
$trustProxies = new TrustProxies(['192.168.1.1'], 'x_forwarded_for');
$noCache = new NoCache('no-cache, max-age=0', pragma: null);
$sslRequired = new SSLRequired(['health/*'], ['testing']);
Passing null for any constructor argument falls back to the corresponding config value.
Testing
Run the package's unit tests:
vendor/bin/phpunit
With coverage:
vendor/bin/phpunit --coverage-text --coverage-clover coverage.xml --log-junit junit.xml
Requires Xdebug or PCOV for coverage reports.
Contributing
Contributions are welcome! Please:
- Fork the repository.
- Create a feature branch (
git checkout -b feature/your-feature). - Commit your changes (
git commit -m 'Add your feature'). - Push to the branch (
git push origin feature/your-feature). - Open a pull request.
License
This package is open-sourced under the MIT License. See the LICENSE file for details.