Skip to main content

Upgrade from lightsaml

litesaml/saml is a high-level rewrite of litesaml/lightsaml. The API is not backwards-compatible — this guide covers every breaking change and shows before/after examples for the most common patterns.

What changed

Arealightsamlsaml
Packagelitesaml/lightsamllitesaml/saml
Namespace\LightSaml\*\Litesaml\*
PHP^7.4^8.4
API styleLow-level XML buildersHigh-level PSR-7 wrappers
BindingsString constants (SamlConstants::*)BindingType enum
CertificatesX509Certificate::fromFile()Certificate(PublicKey, PrivateKey)
IDs / timestampsCaller-managed (Helper::generateID())Managed internally
OutputSerialized XML stringPSR-7 ResponseInterface

1. Package and namespace

composer remove litesaml/lightsaml
composer require litesaml/saml

Update all namespace imports from \LightSaml\ to \Litesaml\.

2. PHP version

litesaml/saml requires PHP 8.4. Update your composer.json require constraint if needed.

3. No more manual message construction

The old API required you to build every SAML object by hand. The new API provides two wrappers — ServiceProviderWrapper and IdentityProviderWrapper — that handle message construction, binding encoding, and optional signing for you.

Sending an AuthnRequest (SP)

Before

use LightSaml\Model\Protocol\AuthnRequest;
use LightSaml\Model\Assertion\Issuer;
use LightSaml\SamlConstants;
use LightSaml\Helper;

$authnRequest = new AuthnRequest();
$authnRequest
->setAssertionConsumerServiceURL('https://my.site/saml/acs')
->setProtocolBinding(SamlConstants::BINDING_SAML2_HTTP_POST)
->setID(Helper::generateID())
->setIssueInstant(new \DateTime())
->setDestination('https://idp.com/sso')
->setIssuer(new Issuer('https://my.site'));

// Serialize and redirect manually...

After

use Litesaml\ServiceProviderWrapper;
use Litesaml\Support\MessageHandler;
use Litesaml\Models\Descriptors\{Sp, Idp, Endpoint, Certificate, PublicKey, PrivateKey};
use Litesaml\Enums\BindingType;
use Nyholm\Psr7\Factory\Psr17Factory;

$factory = new Psr17Factory();
$handler = new MessageHandler($factory, $factory);

$sp = new Sp(
entityId: 'https://my.site',
acs: new Endpoint('https://my.site/saml/acs', BindingType::POST),
slo: new Endpoint('https://my.site/saml/slo', BindingType::REDIRECT),
);

$idp = new Idp(
entityId: 'https://idp.com',
sso: new Endpoint('https://idp.com/sso', BindingType::REDIRECT),
slo: new Endpoint('https://idp.com/slo', BindingType::REDIRECT),
signing: new Certificate(publicKey: new PublicKey(file_get_contents('/path/to/idp-cert.pem'))),
);

$spWrapper = new ServiceProviderWrapper($sp, $handler);

// Returns a PSR-7 ResponseInterface (redirect or POST form)
$response = $spWrapper->sendAuthnRequest($idp);

Sending an AuthnResponse (IdP)

Before

use LightSaml\Model\Protocol\Response;
use LightSaml\Model\Assertion\{Assertion, Issuer, Subject, NameID, Conditions, AttributeStatement, Attribute, AuthnStatement, AuthnContext};
use LightSaml\Model\Protocol\{Status, StatusCode};
use LightSaml\SamlConstants;
use LightSaml\Helper;

$response = new Response();
$response
->addAssertion($assertion = new Assertion())
->setStatus(new Status(new StatusCode(SamlConstants::STATUS_SUCCESS)))
->setID(Helper::generateID())
->setIssueInstant(new \DateTime())
->setDestination('https://sp.com/acs')
->setIssuer(new Issuer('https://idp.com'));

$assertion
->setId(Helper::generateID())
->setIssueInstant(new \DateTime())
->setIssuer(new Issuer('https://idp.com'))
->setSubject(
(new Subject())
->setNameID(new NameID('user@example.com', SamlConstants::NAME_ID_FORMAT_EMAIL))
// ...SubjectConfirmation, conditions, etc.
)
->addItem(
(new AttributeStatement())
->addAttribute(new Attribute(\LightSaml\ClaimTypes::EMAIL_ADDRESS, 'user@example.com'))
);

// Serialize and POST manually...

After

use Litesaml\IdentityProviderWrapper;
use Litesaml\Models\Messages\Attribute;

$idpWrapper = new IdentityProviderWrapper($idp, $handler);

// Returns a PSR-7 ResponseInterface (auto-submit POST form to the SP's ACS)
$response = $idpWrapper->sendAuthnResponse($sp, [
new Attribute('email', ['user@example.com']),
new Attribute('displayName', ['Jane Doe']),
]);

4. Certificates

Before

use LightSaml\Credential\X509Certificate;

$cert = X509Certificate::fromFile('/path/to/cert.crt');

After

use Litesaml\Models\Descriptors\{Certificate, PublicKey, PrivateKey};

// Public key only (for verifying inbound signatures)
$cert = new Certificate(publicKey: new PublicKey(file_get_contents('/path/to/cert.pem')));

// With private key (for signing outbound messages)
$cert = new Certificate(
publicKey: new PublicKey(file_get_contents('/path/to/cert.pem')),
privateKey: new PrivateKey(file_get_contents('/path/to/key.pem')),
);

PublicKey and PrivateKey accept either a full PEM string or a raw base64-encoded DER value.

Signing is automatic: attach a Certificate with a PrivateKey to your Sp or Idp descriptor and all outgoing messages are signed without any additional calls.

5. Bindings

Before

use LightSaml\SamlConstants;

SamlConstants::BINDING_SAML2_HTTP_POST
SamlConstants::BINDING_SAML2_HTTP_REDIRECT

After

use Litesaml\Enums\BindingType;

BindingType::POST
BindingType::REDIRECT

6. Metadata

Building and parsing metadata is now handled by dedicated classes. See Generate metadata and Parse metadata for full examples.

Before

use LightSaml\Model\Metadata\{EntityDescriptor, SpSsoDescriptor, KeyDescriptor, AssertionConsumerService};
use LightSaml\Credential\X509Certificate;
use LightSaml\SamlConstants;

$entityDescriptor = new EntityDescriptor();
$entityDescriptor
->setID(\LightSaml\Helper::generateID())
->setEntityID('https://my.site');

$spSsoDescriptor = (new SpSsoDescriptor())->setWantAssertionsSigned(true);
$entityDescriptor->addItem($spSsoDescriptor);

$spSsoDescriptor->addKeyDescriptor(
(new KeyDescriptor())
->setUse(KeyDescriptor::USE_SIGNING)
->setCertificate(X509Certificate::fromFile('/path/to/cert.crt'))
);

$spSsoDescriptor->addAssertionConsumerService(
(new AssertionConsumerService())
->setBinding(SamlConstants::BINDING_SAML2_HTTP_POST)
->setLocation('https://my.site/saml/acs')
);

After

use Litesaml\ServiceProviderWrapper;
use Litesaml\Support\MessageHandler;
use Litesaml\Models\Descriptors\{Sp, Endpoint, Certificate, PublicKey, PrivateKey};
use Litesaml\Enums\BindingType;
use Nyholm\Psr7\Factory\Psr17Factory;

$factory = new Psr17Factory();
$handler = new MessageHandler($factory, $factory);

$sp = new Sp(
entityId: 'https://my.site',
acs: new Endpoint('https://my.site/saml/acs', BindingType::POST),
slo: new Endpoint('https://my.site/saml/slo', BindingType::REDIRECT),
signing: new Certificate(
publicKey: new PublicKey(file_get_contents('/path/to/cert.pem')),
privateKey: new PrivateKey(file_get_contents('/path/to/key.pem')),
),
);

$spWrapper = new ServiceProviderWrapper($sp, $handler);
$xml = $spWrapper->generateMetadata();