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

lightsaml2/symfony-bridge

Symfony bridge for LightSAML2 that integrates SAML 2.0 service provider and identity provider support into Symfony apps, with bundle configuration, security firewall integration, and endpoints for authentication requests, responses, metadata, and single logout.

View on GitHub
Deep Wiki
Context7

Getting Started

First: establish what this package is before you composer require anything. lightsaml2/symfony-bridge is a Symfony bundle — it registers compiler passes, firewall factories, and DI services for Symfony\Bundle\SecurityBundle. It has no ServiceProvider, no Guard/UserProvider, no config/*.php merge pipeline. In a Laravel app you cannot install it as a dependency. The realistic day-to-day use is as a reference implementation you read and port, or as a probe you run in a throwaway Symfony skeleton to see the correct shape of an SP before hand-rolling the Laravel side.

Where to look first, in this order

  1. DependencyInjection/Configuration.php — the config tree. This is the single most valuable file in the repo. It tells you what an SP actually needs: sp.entity_id, sp.assertion_consumer_service, sp.single_logout_service, sp.private_key/certificate, per-IdP metadata/certificate, and attribute_mapping. Copy this schema into config/saml.php.
  2. Resources/config/services.yml (or .xml) — the wiring list. Enumerate the services it constructs; each one is a class you will need a Laravel equivalent for.
  3. The security factory (Security/Factory/*Factory.php) — the SamlProvider, SamlListener, and token classes. This is the part that does not port; it is the piece you replace with a Laravel guard.
  4. The ACS controller and metadata controller — these port cleanly and are the smallest useful unit of value.

Minimal probe to see it work (Symfony, throwaway app)

# config/packages/security.yaml
security:
    providers:
        saml:
            id: saml_user_provider   # your custom provider
    firewalls:
        main:
            saml:
                provider: saml
                sp:
                    entity_id: 'https://app.test/saml/metadata'
                    assertion_consumer_service: 'https://app.test/saml/acs'
                idp:
                    entity_id: 'urn:test:idp'
                    metadata: '/path/to/idp-metadata.xml'
// config/bundles.php
return [ LightSaml\SymfonyBridgeBundle\LightSamlSymfonyBridgeBundle::class => ['all' => true] ];

Hit /saml/metadata, paste it into your IdP (Okta dev tenant or a local simplesamlphp instance), attempt SP-initiated login, and confirm an assertion round-trips. That is the whole first use case — prove metadata exchange and assertion parsing end to end on a test IdP before you design anything.

Then translate into Laravel — the actual build

// routes/web.php  — three routes, nothing more
Route::get('/saml/metadata', [SamlController::class, 'metadata']);
Route::post('/saml/acs',     [SamlController::class, 'acs'])->name('saml.acs');
Route::get('/saml/sls',      [SamlController::class, 'sls']);   // defer initially
// config/saml.php — derived from the bundle's Configuration.php
return [
    'sp' => [
        'entity_id'    => env('SAML_SP_ENTITY_ID'),
        'acs'          => route('saml.acs'),
        'private_key'  => storage_path('saml/sp.key'),
        'certificate'  => storage_path('saml/sp.crt'),
    ],
    'idp' => [
        'entity_id'    => env('SAML_IDP_ENTITY_ID'),
        'sso_url'      => env('SAML_IDP_SSO_URL'),
        'certificate'  => env('SAML_IDP_CERT'),
    ],
    'attribute_map' => ['email' => 'mail', 'name' => 'displayName', 'role' => 'memberOf'],
];

The underlying engine to depend on is lightsaml/lightsaml (the core library), not this bundle. Budget 2–4 weeks for the guard + ACS + metadata + JIT provisioning if you have not done SAML before. Day one is still composer require --dry-run lightsaml2/symfony-bridge in a scratch branch to confirm the PHP/Symfony constraints — expect it to fail on Laravel 11/12 + PHP 8.3, and let that end the dependency question cleanly.

Implementation Patterns

Pattern 1 — Bundle as a spec, not a dependency. The productive workflow is: read the bundle, extract the three artifacts that carry real value (metadata XML generation, AuthnRequest construction, response-validation orchestration), and re-express them as a Laravel service + route group + guard. Treat every file under Security/ as pseudocode for the guard you are about to write.

Pattern 2 — Config-schema-first porting. Port Configuration.php into a config/saml.php with the same key names. You get three things for free: (a) a config file your ops team can reason about, (b) a natural place for per-tenant IdP blocks later, (c) a diff-friendly surface when you compare your implementation against the bundle and against a maintained alternative (nbgrp/oneloginsaml-bundle, hslavich/OneloginSamlBundle) if you decide to switch engines.

Pattern 3 — Guard + provider, mirroring the firewall. The bundle's SamlProvider becomes a Laravel guard; its user provider becomes your UserProvider. Keep them separate so the guard handles assertion → identity and the provider handles identity → user record.

class SamlGuard implements Guard
{
    public function user()
    {
        $assertion = $this->validator->validate($this->request->input('SAMLResponse'));
        $identity  = $this->mapAttributes($assertion);         // email, name, groups
        $user      = $this->provider->retrieveBySamlIdentity($identity); // JIT here
        return $user; // null on failure -> guard denies
    }
}

Pattern 4 — JIT provisioning in the provider, not the guard. Attribute mapping and user creation are business logic. Emit a SamlUserProvisioned event from the provider so downstream listeners (role sync, welcome email, audit log) do not get baked into auth code.

Pattern 5 — Additive rollout, feature-flagged per tenant. Do not replace your existing session login. Register SAML as an additional guard alongside it, gate it with a per-tenant flag in config, and only promote it to primary once you have run a full login cycle against every in-scope IdP. This mirrors how the bundle's firewall sits next to other authentication listeners in Symfony.

// config/auth.php
'guards' => [
    'web'  => ['driver' => 'session', 'provider' => 'users'],
    'saml' => ['driver' => 'saml',    'provider' => 'users'],
],

Pattern 6 — RelayState carries the intended destination. On SP-initiated login, stash url()->intended() in a signed cookie or session keyed before redirecting to the IdP, and restore it in the ACS handler. Without this every login lands on /.

Pattern 7 — If you have a genuinely mixed Symfony/Laravel estate. Run the bundle in the Symfony service (where it belongs), and have Laravel trust the resulting session/SSO token. Do not attempt to bridge the firewall listener into Laravel — that integration seam does not exist.

Gotchas and Tips

  • The dependency is the trap, not the code. One star, zero dependents. Any bug you find in signature validation is yours to find and patch. If you vendor it, name an owner and set a patch cadence before the first line of ported code.
  • Verify the fork. Confirm lightsaml2/* is actively maintained versus a namespace-squat on an abandoned original. Check last release date, open issues, and whether the bundle references Symfony\Component\Security\Core\Authentication\Token\* classes that were removed in Symfony 6 — that one class-hierarchy change is a common reason these bridges stop loading.
  • Read the assertion-validation path yourself. XSW, canonicalization, XXE, replay windows, clock skew, and encrypted assertions all live in code you are inheriting. "No one has looked at this" is the actual risk profile. Reject an unsigned assertion explicitly; do not rely on the library's default.
  • Clock skew is the intermittent one. Set an explicit acceptance window (typically ±30–60s) and monitor for NotOnOrAfter/NotBefore failures by region — they surface as random login failures that reproduce nowhere.
  • Replay caching across nodes. A shared assertion-ID cache in Redis is mandatory in a horizontally scaled deployment. In-process cache means a replay succeeds on the second node.
  • Certificate rotation is the classic outage. When the IdP rotates its signing cert and your cached metadata does not refresh, logins fail silently from the user's perspective. Alert on ACS error rate, not on support tickets.
  • Debugging workflow: base64-decode the SAMLResponse and pretty-print the XML; inspect with xmlsec1 --verify; use a browser SAML tracer extension to capture the real POST; compare Audience and Recipient against your actual SP entity ID and ACS URL — a trailing slash mismatch is the single most common cause of "it worked yesterday."
  • Proxy gotchas: an ACS endpoint behind a proxy that rewrites POST bodies or strips RelayState will fail in ways that do not reproduce locally. Test through the real ingress.
  • Multi-tenant triples the surface. Per-tenant IdP metadata and certs mean storage, admin UI, rotation, and cache invalidation — price it before committing. The bundle's flat YAML config does not anticipate this; you will be inventing the schema regardless.
  • Extension points worth copying if you do vendor it: the response validator interface and the user provider. Both are the correct seams for policy (allowlist of IdPs, role mapping, JIT rules) — override there rather than forking core classes.
  • Plan a break-glass path. IdP outage means login is unavailable. Document a local-admin login before you enable SAML as primary, and test it.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core