aerialship/lightsaml
SAML 2.0 toolkit for Laravel/PHP to add SSO and identity federation to your apps. Provides helpers for SAML authentication flows, metadata, and certificate handling, making it easier to integrate with common IdPs and SPs.
Installation
composer require aerialship/lightsaml
lightsaml is autoloaded in composer.json.First Use Case: Basic SAML Auth Flow
AuthServiceProvider):
use Lightsaml\AuthnRequest;
use Lightsaml\Binding\RedirectBinding;
$acsUrl = url('/saml/acs'); // Assertion Consumer Service URL
$issuer = 'https://your-app.example.com';
$authnRequest = new AuthnRequest($acsUrl, $issuer);
$binding = new RedirectBinding();
$request = $binding->buildAuthnRequest($authnRequest);
return redirect($request->getLocation());
Where to Look First
src/Lightsaml/.AuthnRequest (for SP-initiated login).Response (for parsing IdP responses).RedirectBinding, PostBinding) for request/response formats.tests/ or examples/ directories in the package (if present).SP-Initiated Login (Redirect Binding)
AuthnRequest with ACS URL and issuer.RedirectBinding to serialize and redirect to IdP.$response = new Response($_POST); // For POST binding
$binding = new PostBinding();
$binding->validateResponse($response);
IdP-Initiated Login (Handle Incoming Responses)
$response = new Response($_GET); // For redirect binding
$binding = new RedirectBinding();
if ($binding->validateResponse($response)) {
$attributes = $response->getAttributes();
// Map attributes to Laravel user (e.g., via `auth()->loginUsingId($userId)`).
}
Logout Requests
$logoutRequest = new LogoutRequest($acsUrl, $issuer);
$binding = new RedirectBinding();
$request = $binding->buildLogoutRequest($logoutRequest);
Metadata Handling
use Lightsaml\Metadata\IdpMetadata;
$metadata = new IdpMetadata(file_get_contents('idp-metadata.xml'));
$acsUrl = $metadata->getSingleSignOnService('urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect');
Laravel-Specific:
RelayState) in the session:
session(['saml_relay_state' => $relayState]);
Route::middleware(['saml.secure'])->post('/saml/acs', 'SAMLController@handleResponse');
User model to hydrate from SAML attributes:
public static function findForSAML(array $attributes) {
return self::where('email', $attributes['email'][0])->first();
}
Error Handling:
try {
$binding->validateResponse($response);
} catch (ValidationError $e) {
Log::error("SAML Validation Failed: " . $e->getMessage());
return redirect('/login')->withErrors(['saml' => 'Invalid response']);
}
Testing:
Lightsaml\Response:
$response = new Response([
'SAMLResponse' => base64_encode($validSamlXml),
'RelayState' => '/dashboard'
]);
Binding Mismatches
RedirectBinding/PostBinding) matches the binding expected by the IdP/SP.HTTP-POST, use PostBinding for the AuthnRequest.Clock Skew
$response->setAllowedClockSkew(300); // 5 minutes in seconds
Signature Validation
$response->setSignatureValidation(false); // Not recommended for production!
Character Encoding
$samlResponse = base64_decode($_POST['SAMLResponse']);
Metadata Expiry
Laravel Session Conflicts
PostBinding, ensure the session is not corrupted by the POST request. Clear or rehydrate the session after handling the response.Enable Verbose Logging
Add this to your config/logging.php to capture SAML XML:
'channels' => [
'saml' => [
'driver' => 'single',
'path' => storage_path('logs/saml.log'),
'level' => 'debug',
],
],
Log raw SAML requests/responses:
Log::channel('saml')->debug('SAML Response', ['raw' => $response->getXml()]);
Validate XML Manually Use an online SAML validator (e.g., SAML Tracer) to debug malformed requests/responses.
Check Certificate Trust If signature validation fails, verify the IdP’s certificate is trusted:
$cert = $response->getSigningCertificate();
openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_SERVER);
Custom Attribute Mapping
Override Lightsaml\Response to map IdP attributes to Laravel users:
$user = User::updateOrCreate(
['email' => $response->getAttribute('email')[0]],
[
'name' => $response->getAttribute('givenName')[0] ?? '',
'saml_uid' => $response->getAttribute('uid')[0]
]
);
Dynamic ACS URLs Generate ACS URLs dynamically based on user roles:
$acsUrl = route('saml.acs', ['role' => 'admin']);
IdP Discovery Implement a dropdown to let users select their IdP, then dynamically generate AuthnRequests:
$idpMetadata = new IdpMetadata($selectedIdpMetadataXml);
$acsUrl = $idpMetadata->getAssertionConsumerService();
Caching Cache SAML responses or metadata to reduce processing overhead:
Cache::remember('idp_metadata', 3600, function () {
return new IdpMetadata(file_get_contents('idp-metadata.xml'));
});
Event Listeners
Dispatch Laravel events for SAML flows (e.g., SAMLLoginAttempting, SAMLLoginFailed):
event(new SAMLLoginAttempting($response));
How can I help you explore Laravel packages today?