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

Lightsaml Laravel Package

mlightsaml/lightsaml

LightSAML is a PHP SAML 2.0 library with message models, bindings, metadata, and XML signing/encryption support. It helps build service provider and identity provider integrations, including in Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

mlightsaml/lightsaml is a protocol library, not a Laravel package. There is no service provider, no config file, no facade, and no HTTP middleware. You composer require mlightsaml/lightsaml and then wire it into your own services. Plan on writing 300–600 lines of glue code for a working SP flow.

Note the repo you linked (DiegoCardosoSenaiSC/lightSAML, 0 stars, 0 dependents) is a fork of the upstream mlightsaml library. Before committing, diff it against lightsaml/lightsaml and mlightsaml/lightsaml on Packagist, pin the exact version in composer.json, and treat the fork as a supply-chain risk if it is not actively maintained.

Where to look first, in order:

  1. LightSAML\Core\Model — AuthnRequest, Response, Assertion, Subject, NameID, Issuer. This is the object model you will actually touch daily.
  2. LightSAML\Core\Binding — HTTP-Redirect and HTTP-POST binding classes. These handle Base64, DEFLATE, and URL encoding for you. Do not reimplement these.
  3. LightSAML\Core\Profiles\WebSso\Sp — the SpSsoProfile (and IdpSsoProfile for the reverse direction). This is the closest thing to a "flow runner" in the library.
  4. LightSAML\Core\Context — ProfileContext, CredentialContext, EndpointContext. Everything is passed around via these DTOs, which is why the library feels verbose.
  5. LightSAML\Core\Store — IdStore, RequestStore, CredentialStore. You will need these for replay protection and to remember the AuthnRequest ID.

First use case — SP-initiated login:

// 1. Build the request
$authn = new AuthnRequest();
$authn->setId($requestId = (string) Str::uuid());
$authn->setAssertionConsumerServiceURL(route('saml.acs'));
$authn->setIssuer(new Issuer(config('saml.sp.entity_id')));
$authn->setDestination(config('saml.idp.sso_url'));

// 2. Persist the request ID (cache, 10 min TTL) for InResponseTo checking
Cache::put("saml.req.{$requestId}", true, now()->addMinutes(10));

// 3. Serialize, sign, and hand to the HTTP-Redirect binding
//    (use the binding class; it does deflate + base64 + urlencode)
return redirect()->away($binding->createRedirectUrl($authn, $relayState));

The ACS endpoint is the inverse: read SAMLResponse from the POST body, bind it with the HTTP-POST binding, verify the signature against the IdP certificate, then validate Destination, Audience, NotBefore/NotOnOrAfter, and InResponseTo.

If your IdP supports it, start with IdP-initiated in local dev because it removes the request/RelayState round-trip and gets you a signed assertion faster.

Implementation Patterns

Wrap the library in one service class. Bind an SamlService (or separate SpService) into Laravel's container and inject configuration. Never call the library from controllers or middleware directly — its API surface is wide and you want a single seam to swap it or mock it.

Build a config array early. The library is credential- and endpoint-oriented; assemble this once:

  • sp.entity_id, sp.acs_url, sp.slo_url, sp.key_path, sp.cert_path
  • idp.entity_id, idp.sso_url, idp.slo_url, idp.cert_path (support an array of certs for rotation)
  • NameID format, requested attributes, and whether to sign requests vs. only verify responses

Credential objects, not raw PEM strings. Use X509Certificate and X509Key, put them in a CredentialContext, and load them from storage/app/saml/ (or a secrets manager). Never commit them; never store private keys in the database unencrypted.

Store only what you need in the session. The canonical pattern:

  1. Cache AuthnRequest ID → RelayState mapping.
  2. On ACS, verify signature.
  3. Verify InResponseTo matches a cached ID; delete the cache entry (replay protection).
  4. Extract NameID and attributes into a plain array.
  5. Auth::login($user) and $request->session()->regenerate() to prevent fixation.
  6. Redirect to the cached RelayState, but only if it is a relative path (open-redirect risk otherwise).

Attribute mapping as a config map. Rather than hardcoding eduPersonPrincipalName, define:

'mapping' => [
    'email' => ['urn:oid:0.9.2342.19200300.100.1.3', 'mail'],
    'name'  => ['urn:oid:2.5.4.42', 'displayName'],
],

Handle both friendly names and OIDs; IdPs differ wildly on this.

Multi-tenant / multiple IdPs. Because the library is stateless, the cleanest pattern is one guard per tenant, with the IdP config resolved from the tenant record. Key your AuthnRequest cache by tenant + request ID so an ACS endpoint can look up the right IdP certificate before verifying. You cannot verify a signature until you know which IdP sent it, so the request ID lookup must happen before signature validation.

Metadata. Generate your SP metadata from the model classes and serve it at a stable URL (/saml/metadata). Cache the IdP metadata XML but refresh daily and re-fetch on unknown signing cert — IdPs rotate certificates.

Testing. Snapshot real SAMLResponse payloads from a local IdP (SimpleSAMLphp or Keycloak) into tests/Fixtures/. Assert: valid response succeeds, tampered XML fails, wrong audience fails, expired NotOnOrAfter fails, replayed ID fails. Disable verification only via an explicit testing flag — never automatically in local, or it will sneak into staging.

Logout. SLO is more painful than login. Most teams ship SP-initiated logout as "clear local session, then redirect to IdP's SLO URL," and skip IdP-initiated logout until a customer complains.

Gotchas and Tips

  • DEFLATE, not gzip. The HTTP-Redirect binding uses raw DEFLATE (gzdeflate), not gzencode/gzip. This is the #1 homegrown bug. Use the bundled binding class.
  • Signatures break on whitespace. XML canonicalization (exclusive C14N) is byte-sensitive. Never pretty-print, re-indent, or re-serialize an XML document between receiving and verifying it. Parse it into DOMDocument once with preserveWhiteSpace = true and keep it intact.
  • Base64 decode before XML parse. The SAMLResponse POST field is Base64-encoded; the Redirect query param is deflate + base64 + URL-encoded.
  • Timestamps are UTC and strict. SAML uses Y-m-d\TH:i:s\Z. PHP's date() respects your server timezone; set date_default_timezone_set('UTC') or use gmdate. Add ~60–120 s of clock skew tolerance to NotBefore/NotOnOrAfter.
  • Audience and Destination are on you. The library validates the XML signature and conditions, but you must still assert Audience equals your SP entity ID, Destination equals your ACS URL, and Recipient matches. Many implementations forget this and are trivially replayable.
  • Signature wrapping (XSW) attacks. Do not write your own //ds:Signature XPath and then trust //saml:Subject elsewhere in the document. Verify the signed element is the exact DOM node you extract data from. The library handles this correctly only if you use its validation path consistently.
  • InResponseTo is mandatory for SP-initiated flows and absent in IdP-initiated flows. Track which kind of flow you're handling. If the assertion has no InResponseTo, treat it as higher risk (and consider requiring RelayState to match).
  • Store assertion IDs (Cache::put("saml.asserted.{$assertionId}", true, ...)) to reject replays, distinct from request ID checks.
  • Error hygiene. The library throws from LightSAML\Core\Exception. Catch broad ValidationException and similar, log the technical detail server-side, and show the user a generic error page. Returning the XML or exception message to the browser leaks your IdP configuration and assertion contents.
  • Logging. Never log a full SAMLResponse at info or error — it contains PII and a bearer-like assertion. Redact it or gate it behind a saml.debug config flag.
  • Certificate loading. Certificates come in PEM with headers or as Base64 bodies; check which constructor form you're passing. Use SHA-256 (sha256) — SHA-1 is rejected by most modern IdPs.
  • Proxy-aware ACS URLs. Behind a load balancer, $_SERVER['HTTP_HOST'] may not match your configured ACS URL. Generate URLs with url()/route() and configure TrustProxies, or the Destination check will fail intermittently.
  • Session / cache driver. Request-ID storage in array cache will fail across requests. Use Redis or database cache in production; file cache is fine for single-node.
  • The fork. Because this repo has zero stars and zero dependents, treat it as a private vendored dependency: pin the version, document why the fork exists, and watch upstream (lightsaml/lightsaml) for security fixes. If you just need SP login, evaluate onelogin/php-saml or simplesamlphp/simplesamlphp first — they are more actively maintained and better documented, even if less "object-oriented."
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