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

Oneloginsaml Bundle Laravel Package

hslavich/oneloginsaml-bundle

A Symfony bundle for adding SAML 2.0 single sign-on via the OneLogin PHP SAML toolkit. Configure your identity provider, generate service provider metadata, and handle SP-initiated or IdP-initiated login and logout with attribute and assertion support.

View on GitHub
Deep Wiki
Context7

Getting Started

Framework reality check first. hslavich/oneloginsaml-bundle is a Symfony bundle, not a Laravel package. It extends Symfony\Component\HttpKernel\Bundle\Bundle, registers services through the Symfony DI container, and hooks into Symfony's security firewall via a custom firewall factory. There is no Laravel service provider, no auto-discovery, and no config publishing. In a Laravel app this package is effectively inert — you would be installing Symfony components for nothing. If your day job is Laravel-only, the honest advice is: don't install this; use the underlying onelogin/php-saml library directly (covered under Gotchas). The rest of this assessment assumes a Symfony context, since that is the only place the bundle does anything.

Minimal path to first login:

  1. composer require hslavich/oneloginsaml-bundle
  2. Register it in config/bundles.php: OneLoginSamlBundle\OneLoginSamlBundle::class => ['all' => true]. Without this, nothing boots.
  3. php bin/console config:dump-reference onelogin_saml — this is the first place to look. It reflects the exact keys your installed version supports (they differ between 1.x and 2.x, and between snake_case and camelCase).
  4. Create config/packages/onelogin_saml.yaml with idp, sp, and security blocks:
onelogin_saml:
    idp:
        entityId: 'https://idp.example.com/metadata'
        singleSignOnService:
            url: 'https://idp.example.com/sso'
            binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
        singleLogoutService:
            url: 'https://idp.example.com/slo'
            binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
        x509cert: '%env(SAML_IDP_CERT)%'
    sp:
        entityId: 'https://app.example.com/saml/metadata'
        assertionConsumerService:
            url: 'https://app.example.com/saml/acs'
            binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
        singleLogoutService:
            url: 'https://app.example.com/saml/slo'
            binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
        privateKey: '%env(SAML_SP_KEY)%'
        x509cert: '%env(SAML_SP_CERT)%'
    security:
        wantAssertionsSigned: true
        authnRequestsSigned: true
    username_attribute: 'email'
  1. Generate an SP keypair (openssl req -x509 -newkey rsa:2048 -nodes -days 3652 ...) and give the IdP admin your SP metadata plus ACS URL.
  2. Implement the two interfaces the bundle expects: SamlUserInterface on your User entity (getUsername(), setSamlAttributes(array $attributes)), and SamlUserFactoryInterface::createUser(string $username, array $attributes): SamlUserInterface as a service.
  3. Wire the firewall:
security:
    providers:
        saml_provider:
            id: onelogin_saml.user_provider
    firewalls:
        main:
            saml:
                provider: saml_provider
                user_factory: App\Security\SamlUserFactory

The first use case to get working is SP-initiated login: user hits your /saml/login action → bundle's OneLogin\Saml2\Auth service builds an AuthnRequest → IdP redirects back with a POST to /saml/acs → the bundle parses and validates the response, calls your factory with the NameID/username and the raw attribute array → you end up with a Symfony token. That loop is 90% of the integration.

Implementation Patterns

  • Put provisioning in the factory. createUser() is where you do find-or-create by NameID/email against your user table (JIT provisioning), and where you persist SAML attributes onto the user. Keep the factory small and pure — it's the easiest part of the system to unit test with fixture attribute arrays.
  • Map groups to roles at login time, not in security.yaml. Derive getRoles() from IdP group attributes inside the factory so IdP-side changes take effect on next login. If you need near-immediate revocation, cap session lifetime or re-read roles in refreshUser().
  • You usually own the thin controller actions (/saml/login, /saml/acs, /saml/slo, /saml/metadata). Inject the OneLogin\Saml2\Auth service (id onelogin_saml.auth — confirm with bin/console debug:container | grep -i onelogin) and call login(), processResponse(), processSLO(), logout(). The ACS must be POST-only.
  • Metadata endpoint: build OneLogin\Saml2\Settings from the same config array, then getSPMetadata() + validateMetadata() and return XML. Cache it; it only changes on cert rotation.
  • Normalize attributes once. Don't sprinkle urn:oid:... attribute names through controllers. Parse the raw array into a small DTO in the factory, store the raw array too for debugging and audit.
  • IdP-initiated flow works but is unsolicited: there is no InResponseTo to verify. Rely on assertion signature validation and configure a default ACS/consumer URL at the IdP.
  • Logout: local /logout alone leaves the IdP session alive. Wire processSLO() both ways and use a LogoutEvent listener for app-specific session cleanup.
  • Multi-IdP / per-tenant: the bundle is one IdP per firewall. Either define one firewall per IdP (different entityIds + ACS paths) or drop to onelogin/php-saml and construct Auth from dynamically built Settings — at that point the bundle is just getting in your way.
  • Testing: unit-test the factory; integration-test the ACS controller by posting a recorded, signed fixture response. Never hit a live IdP in CI.
  • Secrets: certs and private keys in env vars or the Symfony Secrets Vault, never committed YAML. Keep a separate config/packages/dev/onelogin_saml.yaml pointing at a test IdP.

Gotchas and Tips

  • Laravel is not a supported host. If you're on Laravel, composer require onelogin/php-saml, build the settings array in config/services.php, wrap Auth::login() / Auth::processResponse() in a controller, and store the NameID in session. This bundle cannot be adapted without effectively embedding a Symfony kernel.
  • Maintenance risk is real. Last tagged release was 2022-11-23. Run composer why-not hslavich/oneloginsaml-bundle against your Symfony and PHP versions before committing — Symfony 7 / PHP 8.3 are likely outside the constraint set. Budget for a fork or a pin.
  • The protocol library moves faster than the bundle. It wraps onelogin/php-saml (now community-maintained under the SAML-Toolkits org). Security fixes land in the library, not the bundle; audit the library version directly.
  • Cert formatting bites. Use YAML block scalars (|), keep PEM headers consistent, and remember the IdP cert is the signing cert, not its TLS cert. Your SP private key must match your SP public cert — mismatch produces confusing signature failures.
  • ACS URL must match the IdP config string-for-string. Trailing slashes, http vs https, www, and port numbers are the #1 cause of "Invalid response".
  • Reverse proxies break URL derivation. php-saml builds Destination/ACS from the request. Behind a load balancer, set baseurl or Symfony trusted_proxies + x-forwarded-*, or you'll get destination/signature mismatches that look like IdP problems.
  • Signing flags are independent. wantAssertionsSigned, wantMessagesSigned, authnRequestsSigned, logoutRequestSigned. Most IdPs sign only the assertion; turning on wantMessagesSigned without the IdP signing the response breaks login. Change one flag at a time.
  • Encrypted assertions require the SP private key to be loaded correctly; a missing/incorrect key surfaces as a decryption error in getLastErrorReason().
  • Debug with the Auth object, not the stack trace. $auth->getLastErrorReason(), $auth->getLastErrorException(), $auth->getErrors() in the ACS controller before rethrowing. bin/console debug:config onelogin_saml shows resolved config (secrets masked); debug:container shows real service IDs, which differ by version.
  • SAML needs a session. Request ID / InResponseTo validation is session-based. Don't put these endpoints on a stateless firewall, and clear cookies between manual test runs.
  • Clock skew. Assertions are valid for tight windows; container drift or wrong timezone produces "assertion not yet valid".
  • Extension points: custom user factory, replacing the bundle's user provider, decorating OneLogin\Saml2\Auth, and the bundle's security events. If none fit (dynamic IdPs, per-tenant certs), take the library directly — the bundle's value is firewall glue, not protocol handling.
  • Set the firewall entry point to the SAML login path, or unauthenticated users will hit 401 loops instead of being redirected to the IdP.
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
shitoudev/permissionmanager