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

Security Bundle Laravel Package

nti/security-bundle

nti/security-bundle is a Laravel/PHP security package that provides reusable helpers for authentication, authorization, and common hardening tasks, helping teams centralize access control and protect application routes and resources.

View on GitHub
Deep Wiki
Context7

Getting Started

The bundle ships almost no public documentation and has no downstream users to learn from, so treat the source as the spec. Budget 30–60 minutes for a read-through before you write any application code.

0. Confirm the framework actually matches. v2.0.1 is explicitly a Symfony 6 compatibility release. This is a Symfony bundle (config/bundles.php, bin/console, DI extension) — it cannot be dropped into a Laravel app without writing a bridge, and the new release does nothing to change that. If you are evaluating from a Laravel codebase, that is a hard stop unless the functionality is small enough to reimplement.

1. Confirm it actually installs against your stack. The release note is a single untranslated line ("Compatibilidad con symfony 6") with no changelog, no migration guide, and no UPGRADE file. Treat the 1.x → 2.x jump as an undocumented major and check the constraint matrix before committing:

composer show nti/security-bundle --all        # available versions, requires (php, symfony/*)
composer require nti/security-bundle --dry-run # conflicts with your symfony/* pins

Two hard branches now exist:

  • Symfony 6.x → ^2.0. Pin the patch explicitly ("nti/security-bundle": "2.0.1") — 2.0.1 landing shortly after 2.0.0 is itself a signal the major had rough edges.
  • Symfony 4.4 / 5.4 → stay on 1.2.x. Nothing in the release note suggests 1.x is maintained going forward, so plan the upgrade or plan the exit.

2. Register the bundle in config/bundles.php:

Nti\SecurityBundle\NTISecurityBundle::class => ['all' => true],

Verify the class name and namespace case against src/ — a major bump is the usual moment for a namespace tidy-up, and a wrong case fails at container build with a confusing "class not found" in the Flex recipe path.

3. Read these three files in this order — they define the entire usable surface area:

  • DependencyInjection/Configuration.php — the config tree; every knob you can turn.
  • DependencyInjection/NTISecurityExtension.php — how config maps to service definitions, and which services are public/aliased.
  • Resources/config/services.xml (or .yaml) — the actual service IDs and their constructor arguments.

4. Diff 1.2.x against 2.0.1 before upgrading an existing install. The release note covers one line of a major version bump, so the diff is the only migration document you get:

git diff 1.2.3..2.0.1 -- src/ Resources/ composer.json

Look specifically for renamed service IDs, changed config key names, and constructor signature changes — those are what break silently at runtime rather than loudly at boot.

5. Dump the reference config rather than guessing key names (re-dump after the upgrade; it may have changed):

bin/console config:dump-reference nti_security

Confirm the root alias — it is derived from the extension alias, not the package name, and is the single most common first stumbling block.

6. First use case. Pick one concrete service, verify it is autowirable, and inject it into a single application service. Do not spread it across the codebase until you have confirmed behaviour in a test:

bin/console debug:container --show-private | grep -i nti

If the service is private and unaliased, add an alias in config/services.yaml mapping the bundle's concrete class or interface to its service ID.

Implementation Patterns

Wrap, don't scatter. Because the package is effectively unmaintained (0 stars, 0 dependents, one tag in 2024, and a release note that is a single sentence), treat it as a replaceable implementation detail. Define a narrow interface in your own domain namespace and adapt the bundle behind it:

interface TokenSignerInterface { public function sign(string $payload): string; }

final class NtiTokenSigner implements TokenSignerInterface
{
    public function __construct(private readonly \Nti\SecurityBundle\SomeService $inner) {}
    public function sign(string $payload): string { return $this->inner->/* ... */; }
}

Every consumer type-hints TokenSignerInterface. Swapping the bundle out later becomes a one-class change plus a container alias, not a grep across 40 files. On Symfony 6 you can use promoted readonly properties freely in the adapter.

Prefer decoration over forking. If you need to change behaviour, register a decorator in config/services.yaml:

App\Security\LoggingDecorator:
    decorates: nti_security.some_service_id
    arguments: ['@.inner']

Re-confirm the decorated service ID after moving to 2.x — a renamed ID fails at container compile, which is the good failure mode, but only if you have a test that boots the kernel.

Upgrade behind the interface, not across the app. Move to ^2.0 in a branch, run the suite, then flip the Composer constraint on main. Because everything goes through TokenSignerInterface, a failed upgrade is a revert of one dependency line rather than an untangling exercise.

Drive configuration from env vars, not literals. Bundles of this vintage often ship credential-shaped defaults. Bind secrets through %env(...)% in your config and let Symfony's config cache handle resolution:

nti_security:
    api_key: '%env(NTI_SECURITY_API_KEY)%'

Test double at the interface. In config/packages/test/services.yaml, alias your interface to a fake. The bundle's services then never boot in unit tests, which sidesteps network calls and makes CI deterministic. This also isolates you from regressions introduced in 2.0.x patches.

Integration seam. If the bundle registers a security listener or firewall factory, verify it does not silently reorder your existing authenticators. Load your app's security.yaml listeners and confirm the order after enabling the bundle (debug:event-dispatcher on kernel.request). Symfony 6's security component is stricter here than 5.4 — listener ordering and authenticator factory signatures changed, so re-verify even if it worked on 1.x.

Canary rollout. Ship behind a feature flag for one non-critical code path first. With no dependents there is no public evidence of production behaviour under load; you are the first tester — and after a major bump, you are the first tester again.

Gotchas and Tips

Zero dependents is the headline risk, and 2.0.1 does not change it. A single-line release note on a major version is the clearest possible signal that there is no release discipline to lean on. No downstream users means no reported edge cases, no Stack Overflow answers, and no guarantee of a response to issues. Before adopting, check the repo's issue/PR activity and whether the maintainer has committed since the tag. If the code is load-bearing, mirror it into a private fork you control and point Composer at the VCS URL — a deleted upstream repo will otherwise break composer install for everyone.

"Symfony 6 compatible" does not mean "Symfony 6 clean." Changing the constraint is cheap; removing removed-API usage is not. The bundle may boot on 6.4 LTS while still calling deprecated or deleted Symfony 5 APIs on a hot path you do not exercise in smoke tests. Exercise every code path you actually use, with deprecations visible:

SYMFONY_DEPRECATIONS_HELPER=weak bin/phpunit

Then tighten to max[self]=0 and see whether the bundle itself trips the threshold. Suppress by path in phpunit.xml.dist rather than globally — you still want its deprecations surfaced at upgrade time. Note also that "6" is now the ceiling: nothing indicates Symfony 7 readiness, so this dependency caps your framework upgrade path until the maintainer tags again or you fork.

Major-version surface changes are undocumented. Expect at least one of: renamed service IDs, renamed config keys, changed namespace casing, dropped constructor arguments. bin/console lint:container and a kernel-boot test are the cheapest way to find these — they fail at compile rather than at 2 a.m.

Config keys are often unvalidated. Symfony's Configuration.php frequently omits ->cannotBeEmpty() or scalar type checks, so a typo'd key is silently ignored rather than erroring — and a key renamed in 2.x will simply vanish. After any config change, verify the resolved value:

bin/console debug:config nti_security
bin/console cache:clear

debug:config is the fastest way to distinguish "config wrong" from "service not wired." Run it once on 1.x, save the output, and diff it against 2.x after upgrading.

Watch for hardcoded defaults. Grep the source for defaultValue( and for literal strings that look like keys, salts, or IVs. Bundles that predate modern Symfony security practice sometimes ship a static default that is dangerous to leave in place; a compatibility-only release is exactly the kind of release that leaves such defaults untouched.

Private services break autowiring. Older bundles do not register autowire aliases for their interfaces. Symptom: Cannot autowire service ... argument $foo of type Interface. Fix with an explicit alias in services.yaml — do not make services public just to silence the error. Re-check aliases after the upgrade; 2.x may have added or removed them.

Compiler passes are the escape hatch. If the bundle's service definitions need tweaking (tag added, argument replaced) that decoration cannot express, write a CompilerPassInterface in your Kernel::build() and manipulate the container before it is frozen. This is more durable than editing vendor files and more explicit than a config hack — and it is how you patch around a missing Symfony 6 adjustment without forking.

Debugging sequence when something "doesn't work": debug:container nti → debug:config nti_security → config:dump-reference → read the extension's load() → diff 1.2.3..2.0.1. Nine times out of ten the issue is the config root alias or a private-service alias, both visible at step one; after a major bump, the tenth time it is a rename visible at step five.

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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib