Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

N8N Bundle Laravel Package

freema/n8n-bundle

A PHP bundle for integrating n8n workflow automation into your application. Configure n8n connections, trigger workflows via webhooks, and exchange data between your app and n8n automations with minimal setup.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The 2.1.0 release does not change the fundamental finding — freema/symfony-n8n-bundle is a Symfony bundle — but it sharpens why that matters and what the package actually is. The previous assessment treated the bundle as potentially "an HTTP client with Symfony wiring." This release shows the substance is the callback correlation protocol: signed callback URLs dispatched to n8n, an HMAC-SHA256 of the request UUID embedded in the payload's _n8n_bundle block, pending-request handlers persisted to a PSR-6 cache pool and rediscovered in another worker process by getHandlerId() among services tagged n8n.response_handler, and a Symfony event (N8nResponseReceivedEvent) as the join point to application logic.

That is not a library you can cherry-pick. Every mechanism has a Symfony-native analogue in Laravel — PSR-6 cache pool → Illuminate\Cache, DI tag → $this->app->tag()/when, event dispatcher → Illuminate\Contracts\Events\Dispatcher, kernel.secret → APP_KEY — but the port is a reimplementation of the correlation layer, not a copy of a client class. The outbound-only path (fire a webhook, don't care about the answer) remains trivially replaceable by Http::post(). The request/response path is where the bundle earns its existence, and it is also where the Symfony coupling is total.

Integration feasibility. Effectively unchanged as a drop-in: still low. What changed is the calculus between the three paths:

  • Port — now more valuable in principle (signed callbacks, replay protection, cross-worker handler resolution are nontrivial and easy to get wrong) and more expensive in practice (cache pool config, handler registry, secret derivation from app key, event dispatch all need Laravel equivalents).
  • Standalone — now materially harder. The release makes handler registration service-container-driven: a handler constructed with new cannot be found by the process that services the callback. Manual instantiation defeats the mechanism.
  • Sidecar — unchanged; still a bad trade for this surface area.

The honest baseline is now stronger in one direction: a homegrown Http::post() integration will not give you signed, expiring, single-use callbacks, and the 2.1.0 advisory demonstrates that getting that wrong is an unauthenticated write primitive into your response handlers. If you need the callback half, you are choosing between adopting a Symfony bundle and building the protocol yourself. If you only need the outbound half, the package is irrelevant.

Technical risk. High, and this release adds the first concrete data point to what was previously a list of structural concerns:

  • Security history — GHSA-4p4r-j4mr-f8f4: the callback endpoint accepted any POST carrying a _n8n_bundle.uuid, allowing an unauthenticated party to dispatch N8nResponseReceivedEvent with arbitrary data and execute a pending request's response handler. That is a genuine auth bypass in a package with five stars and zero dependents. It was found, disclosed, and fixed — credit due — but it is exactly the class of defect that survives when no one is looking.
  • Version floor — <2.1.0 must be treated as unsafe. Any evaluation artifact, PoC branch, or fork based on 2.0.1 needs the patch or removal.
  • Maturity signal — unchanged: single maintainer, no dependents, no third-party usage evidence. The advisory is now part of that record.
  • Release metadata anomaly — the prior future-dated release (2026-10-01) remains unexplained; still verify tags and CHANGELOG directly.
  • Cross-system breaking change — a hard-coded callback URL in an n8n workflow now receives 401. Upgrading the PHP dependency is not sufficient; the workflows themselves must be edited to post to the callback_url they are handed. This is a coordinated change across two systems owned by different people, which is a scheduling risk as much as a technical one.
  • New operational prerequisites as failure modes — APP_SECRET/n8n.callback.secret must be set (defaults to kernel.secret), and tracking.cache_pool must be shared (Redis) across application servers. Deploy the code without the shared pool and you reintroduce the exact bug 2.1.0 fixes: handlers stored in one worker's filesystem cache are invisible to the worker that receives the callback.
  • Compatibility drift — unchanged; the package remains pinned to one n8n generation.
  • Supply chain — unchanged and now better evidenced: small upside, real blast radius, demonstrated.

Key questions. Revised; items 1–3 from the prior assessment are now partially answered by the changelog itself.

  1. Does the package separate its client from Symfony's container? Answered: no. Handlers must be container-registered services; pending state lives in a Symfony cache pool; the secret derives from kernel.secret.
  2. What is the capability surface? Partially answered: outbound trigger with callback, HMAC-SHA256 signing, expiry, single-use enforcement (409), response handler correlation, event dispatch. Workflow CRUD/executions/credentials remain unconfirmed.
  3. Is the signature compared in constant time? The advisory describes HMAC-SHA256 and expiry, but not the comparison primitive. A === string compare would leave a timing oracle.
  4. How is expiry enforced, and against what clock? Is the expiry bound into the signed material (so it can't be stripped), or merely present in the payload? Clock skew between app servers produces intermittent 401s that look like outages.
  5. What is the replay window? The 409-on-already-handled guard depends on cache TTL. If the TTL is shorter than n8n's worst-case workflow duration, a legitimate late callback is rejected; if the entry is evicted early, a replay succeeds.
  6. Is callback.require_signature configurable to false in production, and is there any warning? A default-true toggle is fine; an undocumented escape hatch that someone flips during an incident is not.
  7. Does the callback controller validate response content, or only authenticity? A validly signed callback carrying an unexpected schema still flows into your handler.
  8. Is there a rate limit or body-size limit on the callback endpoint? Signature verification before parsing helps, but an unauthenticated endpoint still accepts connections.
  9. Which n8n API version and auth model, what are the PHP/Symfony constraints, is transport PSR-18, is there a test suite? Unchanged from the prior assessment.

Integration Approach

Stack fit. Unchanged at install time: expect partial overlap on transitive Symfony constraints, with new exposure on symfony/cache (PSR-6) and symfony/http-foundation. Do not register the bundle in Laravel; treat it as a library at most. Note that Laravel's PSR-6 adapter is a shim over Illuminate\Cache — workable for a port, but the semantics (pool namespacing, tag invalidation, TTL behavior) are not identical and should be verified rather than assumed.

Migration path. Sequence updated for the security release:

  1. Containment (immediate, if applicable) — if any environment, PoC, or fork runs <2.1.0 with the callback route exposed, treat it as a live vulnerability. The endpoint is an unauthenticated path into N8nResponseReceivedEvent and pending response handlers. Patch or remove the route before anything else.
  2. Spike (½ day) — read the source against the nine questions above. The package is now interesting enough to be worth the half-day on its merits, independent of adoption.
  3. Decide — if you need callback correlation, choose deliberately: adopt in a Symfony context, or build it in Laravel. If you need only outbound triggering, stop; the bundle adds nothing.
  4. Fallback / build — the internal app/Support/N8n adapter now has a higher specification bar than the prior assessment implied. A credible Laravel implementation must include: HMAC-SHA256 over the request UUID plus a bound expiry, constant-time comparison, single-use enforcement via Cache::add() keyed to the UUID with a TTL exceeding worst-case workflow duration, a handler registry resolved through the container, and a documented secret with a rotation path. Budget accordingly — this is days, not hours.
  5. Vendor if forking — unchanged: copy, record provenance and MIT license, own the code. If forking a pre-2.1.0 tree, port the advisory fix forward rather than inventing your own.

Compatibility. Pin the n8n server image and the callback contract (URL shape, signature algorithm, expected response schema) next to the client code. For a Laravel-side build, keep the transport on PSR-18/PSR-17 so tests don't require a live n8n. For the Symfony side, note the deprecated callback.route_path — it was never functional, so route definition is now explicitly your routing config; that's a documentation change, not a code one, but it will confuse anyone following older guides.

Sequencing. Outbound trigger first (highest value, lowest risk, and fully replaceable by Http::post()). Inbound callback handling second — but only with signing, expiry, and single-use designed in from the start, not retrofitted; 2.1.0 is a case study in the cost of retrofitting. Workflow/execution CRUD last, if ever; that is where n8n API drift bites hardest.

Operational Impact

Maintenance. Two rules: never run below 2.1.0, and expect the "wait for a stranger" model to fail periodically. The advisory is the demonstration — a low-traffic package sat with an auth bypass in a callback endpoint until someone looked. Forking and vendoring still shifts the burden in-house in a bounded way, but the scope of what you're maintaining just grew: it now includes a signed callback protocol and a cache-backed correlation store, not just an HTTP wrapper. Budget a recurring review line item, and add "subscribe to the repo's security advisories" as a concrete task if you depend on it at all.

Support. Unchanged: no commercial backing, no dependents, no institutional knowledge. The escalation path remains "read the code," now with the added burden that you must be able to read it well enough to audit cryptographic handling. That is a materially different skill requirement than reading a 200-line HTTP wrapper — verify that the owning engineer can actually assess HMAC construction, expiry binding, and replay windows. If not, the build-it-yourself option is not viable either, and the decision becomes "use the bundle in Symfony" or "don't do this integration."

Scaling. The PHP client is still not the bottleneck; n8n's worker and queue configuration is. Two new constraints land on the application tier:

  • Shared cache is now load-bearing. tracking.cache_pool defaults to cache.app, which on a multi-server deployment is per-node storage. Point it at Redis (or an equivalent shared pool) before scaling past one application server, or callbacks will arrive at workers that have never heard of the request. This is not a performance tuning knob; it is a correctness prerequisite.
  • In-flight state has a TTL. Pending handlers live in the cache. Long-running n8n workflows will outlive short cache TTLs unless the TTL is set deliberately against measured workflow duration. Instrument the gap between dispatch and callback and size the TTL from that distribution, not from a guess.
  • Throughput — unchanged: keep outbound triggers on queues with retries and backoff; don't couple user latency to n8n response time.

Failure modes. All prior failure modes stand; the release adds and modifies several:

  • Forged callback — mitigated in 2.1.0 by signature + expiry, provided the secret is set and the endpoint requires signatures. Verify both in config, don't assume the default survived contact with a copy-pasted env file.
  • Handler not found across workers — the bug this release fixes. Reintroduced by any deployment that omits a shared cache pool, or by any handler registered with new instead of as a service. Both are silent: the callback is accepted and quietly dropped.
  • Replayed callback — guarded by the 409-on-already-handled check, which is only as durable as the cache entry. A cache flush, eviction under memory pressure, or TTL expiry reopens the window.
  • Late callback after TTL — legitimate response rejected or orphaned; surfaces as a workflow that "completed" while your app never reacted. Alert on callback-arrived-without-handler.
  • Secret rotation invalidating in-flight callbacks — rotating APP_SECRET or callback.secret breaks every callback dispatched but not yet returned. Needs a dual-secret grace window or a drain-before-rotate procedure.
  • Clock skew — expiry checks fail intermittently across nodes with drifting clocks; looks like auth failure, isn't.
  • Misconfigured n8n workflow — a hard-coded callback URL now yields 401 and the workflow's result is silently lost unless n8n's error workflow alerts on it. This is the most likely upgrade casualty.
  • Retained from before: n8n unavailable, partial execution downstream of an accepted trigger, duplicate execution on retry, auth expiry on the API token, payload schema drift, and inbound forgery if you build the endpoint yourself without the fixes 2.1.0 ships.

Ramp-up. The PHP surface remains small; the learning cost is now split three ways: n8n itself (nodes, error workflows, execution data, credentials), the callback protocol (signing, expiry, replay, correlation TTLs), and the deployment topology that makes the second one work (shared cache, single secret across nodes). A Laravel team can still integrate the outbound path in a day. The callback path is a week to do safely and, if built in-house, a week to build at all. One engineer should own the n8n boundary end-to-end, including secret lifecycle and cache-pool configuration, with the payload and callback contracts documented in the repo.

Net position. Unchanged in direction, strengthened in evidence. The stack mismatch plus a single-maintainer, zero-dependent package still makes adoption as a Laravel dependency hard to justify — and a recently disclosed auth bypass in its callback endpoint is precisely the asymmetry the prior assessment warned about, now observed rather than hypothesized. Two things do shift. First, the package is now more valuable as a reference implementation than as a dependency: 2.1.0 is a compact, readable specification of how to do signed, expiring, single-use callbacks with cross-process correlation, and any in-house Laravel adapter should be checked against it point by point. Second, the bar for that in-house adapter has risen — a naive Http::post() plus an unsigned callback route replicates the vulnerability this release fixes. The correct decision remains: use the package as a reference during a short spike, then build and own a thin Laravel adapter that implements the protocol properly — or, if the callback path isn't actually needed, skip the integration entirely.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource