aporat/laravel-api-middleware
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.
Support
Related Packages
Powerful PHP database abstraction layer (DBAL) with many features for database s...
Laravel Serializable Closure provides an easy and secure way to serialize closur...
Cli error handling for console/command-line PHP applications.