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 Bridge Laravel Package

javer/symfony-bridge

A lightweight bridge for integrating Symfony components into Laravel applications, enabling seamless interoperability between service containers, event dispatchers, HTTP foundation, and other Symfony packages in mixed Symfony/Laravel projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Check your PHP and Symfony versions first. As of 1.6.0 the bridge requires PHP >= 8.1 and supports Symfony 7 (alongside the earlier majors). On a Symfony 7 app this is moot — Symfony 7 itself already requires PHP >= 8.2 — but on Symfony 5.4/6.x with PHP 8.0 or 7.4 you must stay pinned to 1.5.x. Set the constraint explicitly rather than relying on ^1.0 resolution drift:

composer require javer/symfony-bridge:^1.6   # PHP 8.1+, Symfony 6/7
composer require javer/symfony-bridge:^1.5   # older PHP/Symfony

lightsaml/lightsaml is the actual SAML engine; the bridge is a thin Symfony DI wrapper around it. Register the bundle class (check src/ for the exact namespace — traditionally LightSaml\SymfonyBridgeBundle\LightSamlSymfonyBridgeBundle) in config/bundles.php. On Symfony 6/7 that is the only registration step; there is no Flex recipe.

Upgrading from 1.5.x: the 1.6.0 notes list no breaking changes — only Symfony 7 support, the PHP floor, and CI updates. Expect composer update && bin/console cache:clear to be enough, but re-run bin/console debug:container lightsaml --show-private afterwards to confirm the service IDs below survived the DI refactor, and re-run your SAML fixture tests before deploying.

Minimal config. The bundle's configuration tree is the first file to read: DependencyInjection/Configuration.php. Expect something close to:

# config/packages/light_saml_symfony_bridge.yaml
light_saml_symfony_bridge:
    own:
        entity_id: "https://app.example.com/saml/metadata"
        credentials:
            - certificate: "%kernel.project_dir%/config/saml/sp.crt"
              private_key: "%kernel.project_dir%/config/saml/sp.key"
    party:
        idp:
            file: "%kernel.project_dir%/config/saml/idp.xml"   # IdP metadata XML

That config compiles into a small set of services — typically lightsaml.system.own_entity_descriptor, lightsaml.system.idp_entity_descriptor, the credential/trust stores, a time provider, and lightsaml.container.build, which is the factory container you'll actually use in controllers. Read Resources/config/services.xml to confirm the IDs before you autowire anything; don't guess.

First use case: SP-initiated login. Two endpoints, both hand-written controllers:

// LoginController::start
$build = $this->get('lightsaml.container.build');
$own   = $build->getSystemContainer()->getOwnEntityDescriptor();
$idp   = $build->getSystemContainer()->getIdpEntityDescriptor();

$request = new AuthnRequest();
$request->setID(uniqid('', true));
$request->setIssuer(new Issuer($own->getEntityID()));
$request->setDestination($idp->getFirstSsoServiceLocation(Constants::BINDING_HTTP_REDIRECT));
$request->setAssertionConsumerServiceURL($this->generateUrl('saml_acs', [], UrlGeneratorInterface::ABSOLUTE_URL));
$request->setProtocolBinding(Constants::BINDING_HTTP_POST);

$session->set('saml_request_id', $request->getId());
$build->getBindingFactory()->create(Constants::BINDING_HTTP_REDIRECT)->send($request)->send();

Prefer injecting lightsaml.container.build into the constructor over $this->get() — it is clearer, works the same on Symfony 6/7, and makes the dependency visible to static analysis.

Then an ACS controller that receives the POST, decodes the SAMLResponse, validates it, and either logs the user in or throws. Do not skip the request-ID check — see Gotchas.

If you are evaluating this package rather than committing to it: with 0 stars and 0 dependents, read the whole src/ tree (it is small) before wiring it into anything production-facing. 1.6.0 shows someone is keeping it buildable against current Symfony, but the upstream lightsaml/symfony-bridge this forks is still largely dormant scaffolding.

Implementation Patterns

Treat the bundle as a container, not a framework. It gives you a correctly-constructed SystemContainer (own descriptor, IdP descriptor, credential store, trust store, time provider, binding factory) and nothing else — no authenticator, no user provider, no firewall integration. Budget for writing the security glue yourself.

Bridge LightSAML into Symfony Security via a custom authenticator. The cleanest pattern is an AbstractAuthenticator on your ACS route:

public function authenticate(Request $request): Passport
{
    $response = $this->build->getBindingFactory()->receive()->getResponse($httpRequest);
    $this->validator->validate($response);           // signature, destination, audience, timestamps
    $assertion = $response->getFirstAssertion();

    return new SelfValidatingPassport(
        new UserBadge($this->extractNameId($assertion), [$this->userProvider, 'loadUserByIdentifier'])
    );
}

Keep the parsing/validation in a dedicated service (SamlResponseHandler) so it is unit-testable without HTTP. On Symfony 6/7 the authenticator registration is security.firewalls.main.custom_authenticators (or just entry_point) — the doc block style differs from 5.4, so check the version of Symfony you're on before copying snippets from the upstream demo.

Convert Symfony\Component\HttpFoundation\Request to LightSaml\Model\Protocol\HttpRequest once, in a factory or a small kernel listener. LightSAML is transport-agnostic; every binding call needs the converted object. The upstream demo used HttpFoundationFactory/PsrHttpFactory; pick one and hide it behind a service so you can swap it.

Expose metadata with a controller, not a static file. Build the entity descriptor from lightsaml.system.own_entity_descriptor and serialize it with XmlWriter. That keeps the ACS URL and cert in sync with config, and IdPs re-fetch metadata on a schedule.

Attribute mapping: assertions arrive as LightSaml\Model\Assertion\Attribute objects; values are AttributeValue (sometimes with xsi:type, sometimes friendly names). Write a mapper class with an explicit table (mail → email, memberOf → roles) and log unknown attributes rather than guessing. Do not assume NameID is an email — it is often an opaque persistent identifier, so keep a separate saml_subject column on your user table for correlation.

Multi-IdP / multi-tenant: the container.build service is effectively a singleton per IdP. Use a service locator keyed by tenant, build a SystemContainer per tenant at runtime (or register one per IdP via a compiler pass), and pick the locator entry from the ACS URL or RelayState. The bundle config is not designed for N IdPs out of the box; plan for a custom SystemContainer factory.

Test with fixtures. Capture real SAMLResponse XML from a test IdP (Keycloak, SimpleSAMLphp, samltest.id), store as fixtures, and unit-test the handler — signature validation, expired assertions, wrong audience, tampered XML. Add a test that replays the same response twice and asserts the second is rejected (replay protection). Since 1.6.0 raised the PHP floor to 8.1, your test suite can assume PHPUnit 9.5+/10 and PHP 8 attributes — no need to keep 7.4-compatible test scaffolding around.

Gotchas and Tips

  • The bundle validates nothing for you by default. LightSAML gives you response/assertion objects and validators (ResponseValidator, AssertionValidator), but they are not automatically invoked in the flows the demo shows. Explicitly check: XML signature (on response or assertion, per IdP config), Destination, Audience, NotBefore/NotOnOrAfter, InResponseTo against your stored request ID, and replay (one-time use of the assertion ID).
  • InResponseTo and replay are the two most commonly skipped checks. Both need server-side state. The bundle exposes a request store service; use it (or Redis) rather than trusting the RelayState.
  • SameSite cookies will break POST-binding ACS. The SAML response arrives as a cross-site POST; if your session cookie is SameSite=Strict, the user appears anonymous when the IdP posts back. Use Lax (works for top-level POST navigations) or a dedicated cookie on the ACS path. This costs people days.
  • ACS URL must match byte-for-byte, including scheme and host, at the IdP. Behind a reverse proxy or load balancer, force router.request_context and trusted_proxies so generateUrl(..., ABSOLUTE_URL) produces the public URL — otherwise Destination validation fails on a URL like http://internal-lb/....
  • Certificate format confusion. LightSAML expects the PEM body in some places and a full PEM in others. Strip headers with a loader service and cache it; env-var certs with literal \n are a recurring headache — store as base64 and decode at boot.
  • Clock skew. Assertions have a short validity window. Add 60–120s of leeway via a custom TimeProvider and make sure the app servers are NTP-synced. In tests, decorate the time provider rather than sleeping.
  • Binding asymmetry. Redirect = query-string signature, POST = XML-DSig. Both must be tested; some IdPs sign the assertion only, some sign the response only, some both. Make the expected policy explicit in config.
  • XML security settings. Ensure LIBXML_NONET and modern libxml behavior. PHP 8.1+ (now mandatory) disables entity loading by default, so the XXE-era defaults of old lightsaml releases are less of a concern than they were — but do verify the lightsaml/lightsaml version resolved by Composer and don't run the parser against untrusted DTDs.
  • Compile-time config caching. Bundles freeze entity descriptors at container compile time. Changing cert files without cache:clear (or a container rebuild in prod deploy) means the old cert keeps signing. Bake this into your deploy script — and it is doubly important on the 1.5 → 1.6 upgrade, where the DI definitions themselves changed.
  • Deprecation noise on Symfony 6.4. The 1.6.0 changelog mentions Symfony 7 support and CI updates but not deprecation sweeping. After upgrading, run bin/console debug:container lightsaml --show-private and your test suite with SYMFONY_DEPRECATIONS_HELPER=max[self]=0 to see whether the bundle's own definitions still trip Symfony 6.4 deprecations in your app; if they do, they'll become errors on 7.x.
  • Maintenance signal has improved but is still thin. The 1.6.0 release (Symfony 7 / PHP 8.1 / refreshed Actions) means the package is being kept buildable rather than fully abandoned — but it remains 0 stars, 0 dependents, essentially one maintainer, and ~200 lines of DI configuration. Pin to a tag, vendor the small amount of code if you need certainty, and keep SAML parsing isolated behind an interface so you can swap to onelogin/php-saml, SimpleSAMLphp, or hand-wired LightSAML. You are not losing much by replacing it.
  • Debugging tools: the SAML-tracer browser extension, logging the base64-decoded XML before parsing (mask PII), and LightSAML's own logger. Most "signature invalid" reports are actually wrong IdP cert, wrong destination, or a proxy rewriting the URL — check those three first.
  • Extension points worth knowing: override lightsaml.system.own_entity_descriptor or the credential store in services.yaml; decorate the binding factory to add logging; provide a custom TimeProvider for tests; and intercept at the authenticator layer (not the bundle) for anything user-facing.
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.
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
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle