mi-lopez/oneloginsaml-bundle
OneLogin SAML bundle for PHP apps that adds SAML 2.0 single sign-on via OneLogin's toolkit. Configure your identity provider, support SP- and IdP-initiated logins, and map SAML attributes to local users. A lightweight way to add enterprise SSO without building a custom SAML stack.
This is a Symfony bundle, not a Laravel package. It wraps onelogin/php-saml (the official toolkit) and gives you an SP (Service Provider) side implementation: config-driven toolkit wiring, a user interface for attribute hydration, a user provider, and an authenticator you drop into a firewall. If you're in a Laravel codebase, stop here — there is no service provider, no config/onelogin_saml.php, and you'd be better served using onelogin/php-saml directly or a Laravel-specific SSO package.
Minimum path for a Symfony app:
composer require mi-lopez/oneloginsaml-bundleconfig/bundles.php (Flex-compatible bundles usually auto-register; verify — with 0 dependents and 0 stars, don't assume a recipe exists).config/packages/onelogin_saml.yaml. The bundle reads four blocks: idp (entityId, singleSignOnService URL, singleLogoutService URL, x509cert), sp (entityId, assertionConsumerService URL, singleLogoutService URL, privateKey/cert if you sign or encrypt), security (authnRequestsSigned, wantAssertionsSigned, wantMessagesSigned, signature algorithm), and advanced_settings/base_path depending on version.App\Entity\User implementing the bundle's SAML user interface — typically MiLopez\OneloginSamlBundle\Security\User\SamlUserInterface, which requires a setSamlAttributes(array $attributes): void method. This is where you map IdP attributes (mail, uid, groups) onto your own fields.security.yaml: point a custom_authenticator at the bundle's SAML authenticator, set your provider to the bundle's SAML user provider, and make sure the ACS path is public: true (the IdP POSTs there unauthenticated).Where to look first: the bundle's DependencyInjection/Configuration.php. That file is the authoritative schema for the YAML — more reliable than any README, and it tells you exactly which keys the installed version accepts.
First use case: SP-initiated login. Your app redirects to the IdP, the IdP posts an assertion back to the ACS route, the bundle validates it, hands attributes to your setSamlAttributes, and the user provider loads-or-creates the local user. Get that loop working with a single IdP before touching SLO or attribute mapping.
Attribute hydration as a mapper, not business logic. Keep setSamlAttributes a pure translation layer: pull uid, mail, displayName, memberOf out of the array, set fields, return. Resist putting "create team on first login" logic there — it runs on every authentication attempt, not just first login. Use a LoginSuccessEvent listener for provisioning side effects.
One authenticator, one firewall, one IdP. The common failure mode is trying to multiplex IdPs through a single firewall. If you have multiple IdPs, define separate firewalls with separate authenticator service instances, each pointing at a differently-configured toolkit. Sharing one toolkit across IdPs usually means one wrong sp.entityId and one of your IdPs silently rejecting assertions.
Hand the IdP your metadata, don't type URLs by hand. Most versions expose a metadata route or you can build it from the toolkit service. Give the IdP the metadata XML; then the ACS URL and entityId are guaranteed to match on both sides. Copy-pasting URLs is how trailing-slash mismatches get born.
Extend the authenticator rather than replacing it. Subclass the bundle's authenticator when you need custom failure behavior (e.g., redirect to a "your account is not provisioned" page instead of a 403). Override onAuthenticationFailure and onAuthenticationSuccess only; leave assertion validation to the parent — that's the security-critical part and you don't want to reimplement it.
Inject the toolkit service for advanced flows. For IdP-initiated login, forced re-auth (ForceAuthn), or passing RelayState through to a deep link after login, resolve the bundle's toolkit/auth service directly in a controller. This is cleaner than fighting the authenticator's assumptions about entry points.
SLO is a separate workflow — treat it as such. Single Logout means the IdP calls your SLO endpoint and your local logout may need to call the IdP. Confirm which direction the bundle implements in your version, and test it explicitly; it's the part most likely to be stubbed or diverge between versions.
Testing. Run against a real IdP's test tenant when you can, and keep a fixture assertion for unit-testing attribute mapping. If the bundle exposes the toolkit as a container service, you can mock the identity provider config in a test kernel to exercise the ACS controller without a live IdP.
composer.json and read Configuration.php and the authenticator's constructor signature for that version. Symfony 5/6/7 compatibility is not guaranteed across releases; check the composer.json constraint before assuming it installs into your app.x509cert values must be PEM bodies without -----BEGIN CERTIFICATE----- headers or line-wrapping issues in YAML. A cert that works in your browser-based SAML debugger will still fail here if the whitespace is off.notBefore/notOnOrAfter failures ("assertion is not yet valid" on a correctly-configured IdP) are almost always NTP drift on the SP host. The toolkit has a clock-skew setting; use it sparingly as a diagnostic, not a permanent fix.sp.assertionConsumerService.url must be byte-identical to what the IdP has registered, including scheme, host, port, and trailing slash. A mismatch produces a generic "invalid response" with no hint that the URL is the cause.dump(). The underlying toolkit has its own logger; route it to a dedicated channel and raise the level to debug temporarily. Assertion failures surface as OneLogin\Saml2\ValidationError — catch and log the class/message, never the raw assertion (it may contain PII and a signature you don't want in logs).LoginSuccessEvent listener for post-authentication work. Prefer these over forking the bundle — with this project's maintenance profile, a fork is a permanent liability.onelogin/php-saml. That's fine for a single IdP integration you can read end-to-end in an afternoon; it's a poor fit for multi-tenant SAML, where you'll want a bundle with an active maintainer or a direct, thin wrapper around the toolkit you control.How can I help you explore Laravel packages today?