Skip to content

About

Slim 4 adapter for guard-core-php: composes the psr15-guard PSR-15 middleware into Slim's App with factory wiring, app and route-group attachment, and body-parsing order guidance

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

Guard Core


Slim 4 adapter for [guard-core-php](https://github.com/Guard-Core/guard-core-php): wires the guard into Slim's middleware stack. It composes [psr15-guard](https://github.com/Guard-Core/psr15-guard) (the PSR-15 middleware adapter for the same engine) and adds the Slim-native integration layer: PSR-7 factory wiring from Slim's `App`, one-call attachment to the app or a route group, and the body-parsing ordering guidance. Works with Slim 4.

Packagist version Docs Release License CI

PagesBuildDeployment DocsUpdate last-commit

Slim PHP Downloads

Website · Docs · Playground · Dashboard · Discord


Ecosystem

Guard Core is the Python engine. Framework adapters are thin wrappers that translate native request/response types into Guard Core's protocols. The telemetry agents ship security events and metrics to the monitoring backend. Parallel engine implementations exist for Go, PHP, TypeScript (on npm), and Rust (on crates.io) - all ports of the same reference semantics, conformance-tested against the shared adversarial corpus.

Python

Package Role PyPI
guard-core Framework-agnostic security engine PyPI
guard-agent Telemetry agent PyPI
fastapi-guard FastAPI / Starlette adapter PyPI
flaskapi-guard Flask adapter PyPI
djapi-guard Django adapter PyPI
tornadoapi-guard Tornado adapter PyPI

Go

Go modules published via GitHub releases. Production-ready.

Package Role Release
guard-core-go Go engine release
nethttp-guard net/http adapter release
gin-guard Gin adapter release
echo-guard Echo (v4) adapter release
fiber-guard Fiber (v3) adapter release
guard-agent-go Telemetry agent release

PHP

Published on Packagist under the rennf93 vendor. Production-ready.

Package Role Packagist
guard-core-php PHP engine Packagist
laravel-guard Laravel adapter Packagist
symfony-guard Symfony adapter Packagist
psr15-guard PSR-15 adapter Packagist
slim-guard Slim 4 adapter Packagist
guard-agent-php Telemetry agent Packagist

TypeScript / JavaScript

Published under the @guardcore npm scope; source in the guard-core-ts monorepo. Production-ready.

Package Role npm
@guardcore/core Core engine
@guardcore/express Express adapter npm
@guardcore/nestjs NestJS adapter npm
@guardcore/fastify Fastify adapter npm
@guardcore/hono Hono (edge) adapter npm
guardagent Telemetry agent npm

Rust

Published on crates.io. Production-ready.

Package Role crates.io
guard-core-engine Core engine crate crates.io
guard-core-rs Facade crate (consumer entry point) crates.io
actix-guard-rs Actix Web adapter crates.io
axum-guard-rs Axum adapter crates.io
tower-guard-rs Tower adapter crates.io
rocket-guard-rs Rocket adapter crates.io
guard-agent-rs Telemetry agent crates.io

AI Coding Agents

Package Role PyPI
guard-core-mcp MCP server: config validation, docs search, detection sandbox PyPI

Features

  • The full guard-core-php engine pipeline in Slim 4's middleware stack: rate limiting, IP lists, payload inspection, security headers
  • Composition over duplication: wires psr15-guard rather than re-implementing it

Documentation

📚 Documentation - full technical documentation for this package.

🛡️ Guard Core - the engine's reference documentation.

🤖 Monitoring Agent Integration - monitor your Guard instance with a monitoring agent.


Design: composition, not duplication

Slim 4 middleware IS PSR-15 middleware (psr/http-server-middleware), and psr15-guard already provides exactly that. slim-guard does not copy it. It requires psr15-guard and contributes only what is Slim-specific:

  • Factory wiring: SlimGuard::forApp($app, $engine) takes the ResponseFactoryInterface from Slim's App and resolves a matching StreamFactoryInterface (explicit argument, response factory that is also a stream factory, or the default slim/psr7 implementation when installed).
  • Attachment: addTo($app) calls Slim's App::add(); addToGroup($group) attaches to a route group with its documented semantics.
  • Ordering guidance for Slim's optional BodyParsingMiddleware, which consumes the request body stream.

The relationship is deliberate: slim-guard is the ecosystem's Slim flavor of the PSR-15 adapter, and psr15-guard remains the single place where guard verdicts become PSR-7 responses.

Install

composer require rennf93/slim-guard

Usage

Attach the guard where your Slim App is assembled:

use RenzoFranceschini\GuardCore\Config\SecurityConfig;
use RenzoFranceschini\GuardCore\Engine\GuardEngine;
use RenzoFranceschini\GuardCoreSlim\SlimGuard;
use Slim\Factory\AppFactory;

$app = AppFactory::create();

SlimGuard::forApp($app, new GuardEngine(new SecurityConfig(
    enableRedis: false,
    blacklist: ['192.0.2.0/24'],
    rateLimit: 100,
    rateLimitWindow: 60,
    enableRateLimiting: true,
)))->addTo($app);

Blocked requests get the engine's block verdict translated to a PSR-7 response by psr15-guard: 403 Forbidden for a blacklisted IP, 429 Too many requests with Retry-After for a rate limit hit. Passing requests continue into Slim's middleware stack untouched.

Telemetry agent and dynamic rules

The adapter forwards an optional agentHandler to the engine (GuardEngine::setAgentHandler()), so security events, metrics and dashboard dynamic rules flow through guard-agent-php. Install it with composer require rennf93/guard-agent-php, create and start the agent where the Slim App is assembled, pass it as the agentHandler argument, and declare it in the config with enableAgent: true:

use RenzoFranceschini\GuardAgent\GuardAgent;
use RenzoFranceschini\GuardCore\Config\SecurityConfig;
use RenzoFranceschini\GuardCore\Engine\GuardEngine;

$agent = new GuardAgent([
    'apiKey' => $_ENV['GUARD_API_KEY'],
    'endpoint' => 'https://api.guard-core.com',
    'projectId' => 'my-project',
]);
$agent->start();

$config = new SecurityConfig(
    enableRedis: true,
    enableAgent: true,
    enableDynamicRules: true,
    dynamicRuleInterval: 300,
    enableEnrichment: true,
    agentProjectId: 'my-project',
);

SlimGuard::forApp($app, new GuardEngine($config), agentHandler: $agent)->addTo($app);

// or with the plain constructor
$guard = new SlimGuard($app->getResponseFactory(), $streamFactory, new GuardEngine($config), agentHandler: $agent);

register_shutdown_function(static function () use ($agent): void {
    $agent->flushBuffer();
    $agent->stop();
});

enableDynamicRules and enableEnrichment require enableAgent, and dynamic rules need an agent handler that exposes getDynamicRules() (GuardAgent does). The engine builds the dynamic rule manager itself and checks for new rules on the first request and then every dynamicRuleInterval seconds (default 300, minimum 60), because a PHP request process has no background loop. Without an agent handler the engine warns and stays on the static config. agentStats() on the adapter reports {enabled: false, degraded: false} without a handler and merges the handler's getStats() map with one.

Response modifier

SecurityConfig::customResponseModifier is a Closure(GuardResponse): GuardResponse that the engine applies once to every response it returns itself (blocks, redirects and the fail-closed response), after the security headers and before the CORS verdict headers. This adapter applies the same modifier to the pass-through responses it sends, through GuardEngine::applyResponseModifier(), including excluded-path responses and responses of requests that bypass all checks, and it never applies it twice to a response the engine already modified. The order on a pass-through response is security headers, modifier, then CORS verdict headers, so the CORS policy has the last word on its own headers.

use RenzoFranceschini\GuardCore\Request\GuardResponse;

$config = new SecurityConfig(
    customResponseModifier: static function (GuardResponse $response): GuardResponse {
        $response->headers()->set('X-Served-By', 'edge-1');

        return $response;
    },
);

The modifier sees the status, the headers (Set-Cookie is not exposed) and the body, and the changes are merged back onto the PSR-7 response; a response whose body stream is not seekable keeps its body (only its status and headers can change). A modifier that throws leaves the response unmodified. Nothing is read from the response while no modifier is configured. The modifier seam needs guard-core-php 4.4.0 or later.

Lifecycle

PHP shared-nothing applies: construct GuardEngine per request in classic FPM, or per worker under long-running runtimes (FrankenPHP, RoadRunner, workerman). SlimGuard and the composed psr15-guard middleware hold no mutable state of their own. In-memory fallbacks are per-request safety nets; distributed rate limits, IP bans, and cloud-range caches require Redis (set enableRedis: true and point REDIS_HOST/REDIS_PORT at your instance).

Behavior notes

  • Fail-closed is inherited from psr15-guard: if the engine throws, the composed middleware returns the engine's fail-closed response (500 Security check failed, honorably overridden by customErrorResponses) instead of letting the request through.
  • Bounded body read is inherited from psr15-guard: the request body is scanned as a prefix of at most 256 KiB (matching the engine's full-scan window). Payloads beyond the prefix, or signatures split across its boundary, are not detected.
  • Middleware order matters: add the guard so it executes before any middleware that reads the request body stream (Slim's BodyParsingMiddleware casts the stream to a string, which leaves the read pointer at EOF). In Slim, the last middleware added executes first.
  • App-level attachment (addTo) screens everything that reaches the app, including unmatched routes that would 404. Group-level attachment (addToGroup) only screens requests that match a route inside the group; a blacklisted IP hitting an unmatched path under the group is answered by Slim's 404, not the guard's 403.
  • Security headers and CORS: the adapter computes none of them. On a pass-through response the composed psr15-guard middleware merges the engine's security header set, then the engine's customResponseModifier output, then the engine's CORS verdict headers (CORS last, so the CORS policy wins on a shared header name). Blocked responses are exact translations of the engine's verdict.

Testing

composer lint
composer test

composer test runs the plain-PHP suite in bin/test_slim.php (unit coverage always; set REDIS_HOST to a reachable Redis to include the shared-state integration cases).

Status

Install the latest release from Packagist. The composed PSR-15 adapter is rennf93/psr15-guard. The engine floor is rennf93/guard-core-php ^4.4.0, which provides GuardEngine::applyResponseModifier() and the agent and dynamic rule validation described above.

License

MIT

About

Slim 4 adapter for guard-core-php: composes the psr15-guard PSR-15 middleware into Slim's App with factory wiring, app and route-group attachment, and body-parsing order guidance

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages