Skip to content
camada
Menu

Quickstart

Laravel quickstart

Installed from GitHub (camada-app/camada-php).

1. Install

Not on Packagist yet. Run these in your project's folder: Composer installs it straight from GitHub, composer.lock pins the commit, and composer update camada/camada moves it.

composer config repositories.camada vcs https://github.com/camada-app/camada-php
composer require camada/camada:dev-main

2. Environment

The key is printed once when you create a project in the app. Laravel loads .env into the environment, except once php artisan config:cache has run: there, set them as real environment variables.

.env
CAMADA_KEY=<ingest_token>.<snap_token>
CAMADA_INGEST_URL=http://localhost:8787   # dev only; defaults to production ingest

3. Wire it in

// bootstrap/app.php (Laravel 11+), inside the existing ->withMiddleware(function (Middleware $middleware) { … })
$middleware->prepend(\Camada\Laravel\Middleware::class);   // first in the global stack

// or app/Http/Kernel.php (Laravel 10): the first entry of protected $middleware = [ … ]
\Camada\Laravel\Middleware::class,
  • Prepend it so blocked requests never reach the rest of the stack.
  • terminate() is the post-response phase: the spool ships and the snapshot refreshes after the kernel has sent the response.

4. Add the beacon to HTML pages

Optional but recommended. The beacon cuts false positives by showing which sessions are real browsers. Use the helper.

// routes/web.php
use Camada\Camada;
use Illuminate\Http\Request;

Route::get('/', function (Request $request) {
    $ctx = $request->attributes->get('camada');   // the middleware put it there
    return '<html><head>' . Camada::default()->scriptTag($ctx) . '</head><body>…</body></html>';
});

5. Send app outcomes

Login failures, signups and checkout declines are the signals no edge position sees. The identifier is HMAC-hashed in your process. How they catch credential stuffing.

// in a route or controller, once your own sign-in check fails ($email: the account it was for)
\Camada\Camada::default()->track($request->attributes->get('camada'), 'login_failed', $email);

Runtime

What it does per request

  1. Keeps the snapshot in a file-backed cache every worker shares (CAMADA_CACHE_DIR) and refreshes it in the post-response phase, after the client has its bytes. An empty cache answers the first request open.
  2. Resolves the client IP from REMOTE_ADDR per your trusted-proxy setting. Raw X-Forwarded-For is never trusted without it; behind nginx real_ip the peer is already the client, so say none.
  3. Your ordered custom rules first, then allow, block, challenge. A block gets a 403 with x-block-reason before your app runs; a challenge serves the proof-of-work page on a page load, and an API call reaches your app with an x-camada-challenge: 1 response header. The event still ships.
  4. Serves /_cam/b.js (the beacon, first-party, from opcache) and relays /_cam/fp posts onto the event spool with the resolved client IP.
  5. Sets x-rid and the _sfp session cookie, and after the response has ended appends one redacted event to the spool; a due spool ships in that same post-response phase.

Limits

Caveats at this position

  • Enforcement at this position covers IP, path, user-agent and request-header conditions. ASN, country and TLS-fingerprint entries fail open in-app.
  • Header order is whatever getallheaders() yields, so the analyst reads no HEADER_ORDER signal from this tap and never scores its absence.
  • Under FPM and FrankenPHP the post-response work runs after fastcgi_finish_request(); under php -S and mod_php the buffer is flushed with a Content-Length first. Run the CLI server with PHP_CLI_SERVER_WORKERS=4 or more.
  • The cache dir must be a local, writable directory (flock and rename are the concurrency model). Each host keeps its own copy and ships its own spool.
  • Events ship when the spool is due, on the next request that finds it due: a quiet site ships its last events on its next hit, not on a timer.

Kill switch: CAMADA_DISABLED=1, checked per request. All other variables are listed in the docs index; the package's options and deployment notes are on the PHP page.