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

Symfony Authenticator Restrictor Bundle Laravel Package

halloverden/symfony-authenticator-restrictor-bundle

A Symfony bundle for restricting which authenticators are available in your application. Configure rules to control when specific authentication methods can be used, giving fine-grained control over login flows without custom security code.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle (not a Laravel package) — there is no guard/middleware analogue here, so if you're in a Laravel codebase the equivalent is per-guard route groups with auth:<guard> middleware, and this bundle offers nothing. For a Symfony service running multiple authenticators inside a single firewall, this bundle lets you scope which authenticator runs on which route.

1. Verify the source before you install. At 0 stars, 0 dependents, and no visible release cadence, this is a "read all ~100–200 lines" package, not a "trust the abstraction" package. Look at, in order:

  • src/ for an Attribute/ folder — determines whether restriction is attribute-driven (on controllers) or config-driven.
  • DependencyInjection/ and any CompilerPass — this is where authenticators get decorated and where the matcher semantics live.
  • The request matcher itself — find out exactly what is matched (route name? path regex? method? host?) before you write a single config line.

2. Install and register.

composer require halloverden/symfony-authenticator-restrictor-bundle

Bundles generally do not auto-register on a plain Symfony install:

// config/bundles.php
return [
    // ...
    Halloverden\SymfonyAuthenticatorRestrictorBundle\SymfonyAuthenticatorRestrictorBundle::class => ['all' => true],
];

3. Clear the cache — this bundle works at container-compile time, so bin/console cache:clear is part of the install, not an afterthought.

4. First use case to reach for: a firewall that hosts both a form login and an API token authenticator, where POST /api/* should only ever hit the token authenticator and /login should only ever hit the form. Before this bundle the usual answer is splitting the firewall by pattern, which duplicates context, remember_me, logout, and access-control config and breaks shared sessions. Keep one firewall, scope the authenticators by route.

Start with a spike branch and an integration test asserting both the allowed route and the denied route. The value proposition is a negative control — an authenticator that must not fire — so a smoke test that only proves the happy path proves nothing.

Implementation Patterns

Configure allowed authenticators per firewall / request context. The core usage is a mapping from authenticator service IDs to route or path patterns. Confirm the exact key names against the source rather than guessing — a wrong service ID is the most common silent failure mode (see Gotchas).

Incremental auth modernization (the strongest pattern). Adding passkeys, OAuth2/OIDC, or an API-token authenticator alongside a legacy form login is normally a big-bang cutover. Instead, land the new mechanism scoped to /app/* while /legacy/* keeps the old one. Same firewall, same context — sessions stay shared across the migration window. This shortens the migration and is a real de-risking lever for a roadmap item.

Isolate JSON login from token auth. JSON-login authenticators that short-circuit on POST and token authenticators that throw on non-API paths produce bugs that look like routing problems but are auth-ordering problems. Multiple authenticators in one firewall mean every authenticator sees every request. Scoping them by route removes the interference with a narrow blast radius.

Treat it as a decorator, and prototype the decorator first. The capability is small: a request matcher plus an AuthenticatorInterface decorator and a compiler pass that wires it into the service definitions. If you need more than about a day of engineering to reproduce it, use the package; if you can write it in ~50 lines, prefer first-party code — it removes a dependency from your authentication path and you own the test suite. Either way, put it behind a feature flag until one full release cycle has passed.

Test matrix, not smoke tests. Enumerate every authenticator × route pair and assert the allow and the deny:

  • POST /api/thing with the token authenticator allowed, form authenticator denied.
  • GET /login with form allowed, token denied.
  • An unmatched route — assert whatever the package's default is (permit or suppress) explicitly, because that default is the highest-severity failure surface.
  • A renamed route and a changed path prefix, to catch matcher fragility.
// Sketch — the intent matters more than the exact helper names
$this->client->request('POST', '/api/thing', server: ['CONTENT_TYPE' => 'application/json']);
$this->assertResponseIsSuccessful();

// Negative control: the form authenticator must NOT process this
$this->client->request('POST', '/login');
$this->assertResponseStatusCodeSame(401);

Keep it off the hot path when you can. Runtime cost is a request matcher evaluation per request — negligible — but do not stack it with other request-time decorators that also short-circuit the authenticator pipeline. Compiler-pass ordering is the place where two such bundles collide.

Gotchas and Tips

Verify the unmatched-route default before anything else. If the bundle is wrong in either direction when no pattern matches, you get an auth bypass (weaker authenticator silently active) or a lockout (the only authenticator suppressed, 401s in production for a subset of traffic). Read the matcher and write the test that proves it.

Route-name matching is fragile against renames. Path matching is fragile against prefix/locale changes. Whichever you choose, note it in the runbook and add a test that fails if the route is renamed or the API prefix changes. This is the most likely production break.

A config typo is a silent no-op. Wrong authenticator service ID or wrong route name and the bundle simply does nothing — which looks like success until an audit. After wiring config, verify the compiler pass actually rewrote the service definition (dump the container or add a temporary assertion) rather than assuming.

Check lazy firewalls, stateless firewalls, and multi-authenticator firewalls explicitly. Lazy firewalls and the authenticator deprecations in Symfony 6.x/7.x are where auth internals churn. Confirm the declared symfony/security-bundle and PHP constraints against your platform — run composer why-not in CI before merging.

Test sub-requests, ESI fragments, and forwarded requests behind a proxy. Matcher semantics can differ there, and the failure will not show up in a happy-path test.

Upgrades will break loudly or badly. Compiler-pass ordering conflicts surface at container compile time (good) or at runtime (bad). Budget a day or two per Symfony major upgrade. Most likely real-world cost isn't the upgrade itself — it's upstream going quiet and its framework constraint capping your Symfony version, blocking the upgrade.

Plan to fork. Zero stars, zero dependents, no advisories channel, and no maintainer responsiveness guarantee means a vulnerability scanner will never emit an advisory for it — the fork is the security control. Pin the exact version in composer.lock, add it to the dependency allowlist, and record an owner and a fork plan in the risk log.

Write the onboarding note that actually matters. Not docs for the bundle — an internal note recording the matcher semantics, the unmatched-route default, and the path to the test that proves it. That's what the next person needs at 2 a.m., and it is the deliverable regardless of whether you adopt the package or reimplement the pattern.

When to skip it entirely: a firewall pattern, a custom RequestMatcher, entry_point, security.access_control, or per-route IS_AUTHENTICATED_* rules already express the constraint — or expressing it that way doesn't force a firewall split. Native config wins every time; it's supported, documented, and survives upgrades.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource