Most SAML guides assume a single identity provider. A client's platform, which I worked on, needed two — one for internal staff, one for external delegates — each with different attribute mappings and session lifetimes. Here's the implementation.
Module setup
The samlauth contrib module supports multiple IdP configurations from Drupal 10.1 onwards via config entities. Each IdP gets its own config entity with its own certificate, SSO URL, and attribute mapping.
# Install
composer require drupal/samlauth
drush en samlauth -y
# Two config entities:
# saml_idp.internal_staff
# saml_idp.external_delegatesThe attribute mapping problem
Internal staff authenticate through an Azure AD IdP that sends mail and displayName. External delegates authenticate through a custom IdP that sends email and cn. Different attribute names for the same concepts — and the samlauth module needs to know which is which per IdP.
Key insight: Always log the full SAML response during development. Use the samlauth debug mode or add temporary \Drupal::logger calls in your EventSubscriber. The attribute names your IdP sends rarely match what you expect, and silent mapping failures are the most common cause of "user logged in but has no roles."
The session edge case
When a user authenticates via IdP A and then visits a route that triggers IdP B's assertion, Drupal's session handler merges the assertions by default, which corrupts the role assignment. The fix is a custom EventSubscriber on SamlauthUserSyncEvent that checks which IdP originated the assertion before applying roles.
class SamlRoleSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents(): array {
return [SamlauthEvents::USER_SYNC => 'onUserSync'];
}
public function onUserSync(SamlauthUserSyncEvent $event): void {
$idp_id = $event->getSamlData()['idp_entity_id'] ?? '';
if (str_contains($idp_id, 'internal-staff')) {
$event->getAccount()->addRole('internal_staff');
}
elseif (str_contains($idp_id, 'external')) {
$event->getAccount()->addRole('external_delegate');
}
}
}"SAML problems are always either a certificate issue, a clock skew issue, or an attribute mapping issue. Usually all three."