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();