SAML 2.0 Provider
Configure Passport as a SAML 2.0 Identity Provider — publish metadata, configure signing certificates, and map user attributes to SAML assertion statements.
SAML Overview in Passport
In the SAML 2.0 protocol, Passport is the Identity Provider (IdP) and your enterprise application is the Service Provider (SP). Passport authenticates the user and issues a signed SAML Assertion containing the user's identity and attributes. The SP validates this assertion and establishes a local session.
Always start by exchanging metadata. Give the SP your IdP metadata URL: GET /passport/saml/metadata. Then upload the SP's metadata into Passport. This automates endpoint discovery and certificate exchange.
IdP Metadata
Passport publishes a standards-compliant SAML 2.0 metadata document. Provide this URL to your SP's administrator — most enterprise SaaS platforms accept a metadata URL directly.
GET /passport/saml/metadata
Content-Type: application/samlmetadata+xml
<?xml version="1.0"?>
<EntityDescriptor
xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
entityID="https://passport.bizfirst.ai/saml">
<IDPSSODescriptor
WantAuthnRequestsSigned="true"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIID...base64-encoded-cert...</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<SingleLogoutService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://passport.bizfirst.ai/passport/saml/slo"/>
<SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://passport.bizfirst.ai/sso/provider/{consumerKey}"/>
<SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://passport.bizfirst.ai/sso/provider/{consumerKey}"/>
</IDPSSODescriptor>
</EntityDescriptor>
Entity ID and Endpoints
| Field | Value | Notes |
|---|---|---|
| Entity ID | https://passport.bizfirst.ai/saml | Register this in your SP as the IdP entity ID |
| SSO URL (POST) | /sso/provider/{consumerKey} | HTTP POST binding — preferred for enterprise apps |
| SSO URL (Redirect) | /sso/provider/{consumerKey} | HTTP Redirect binding — used for IdP-initiated flows |
| SLO URL | /passport/saml/slo | Single Logout endpoint |
| Metadata URL | /passport/saml/metadata | Auto-updating — include in SP configuration |
Signing Certificate
Passport signs all SAML assertions with an RSA-2048 X.509 certificate. The certificate is embedded in the metadata document and is automatically used by SPs that consume the metadata URL. Certificate rotation is supported without downtime.
Certificate Rotation (Zero-Downtime)
Generate New Certificate
In Passport Admin, navigate to Security → Signing Certificates → Generate New. The new certificate is added to the metadata with use="signing" while the old one remains active.
SP Picks Up New Certificate
SPs that consume the dynamic metadata URL automatically pick up the new certificate on their next metadata refresh (typically 24 hours). For SPs with static certificate configuration, update them manually.
Switch Primary
After all SPs have updated, promote the new certificate to primary. Passport now signs new assertions with the new key.
Revoke Old Certificate
Once the rotation window has closed (typically 48 hours), revoke the old certificate. It is removed from the metadata document.
SAML Assertion Structure
A successful authentication produces a signed SAML Assertion. The structure includes:
<saml:Assertion
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
Version="2.0"
IssueInstant="2026-05-25T10:00:00Z"
ID="_unique-assertion-id">
<saml:Issuer>https://passport.bizfirst.ai/saml</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<!-- RSA-SHA256 signature over assertion -->
</ds:Signature>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
user@example.com
</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
Recipient="https://sp.example.com/saml/acs"
NotOnOrAfter="2026-05-25T10:05:00Z"
InResponseTo="_original-request-id"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2026-05-25T09:59:00Z"
NotOnOrAfter="2026-05-25T10:05:00Z">
<saml:AudienceRestriction>
<saml:Audience>https://sp.example.com/saml</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AttributeStatement>
<saml:Attribute Name="email">
<saml:AttributeValue>user@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="firstName">
<saml:AttributeValue>Jane</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="lastName">
<saml:AttributeValue>Smith</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="roles">
<saml:AttributeValue>manager</saml:AttributeValue>
<saml:AttributeValue>finance-user</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
NameID Formats
| Format | Value | Use Case |
|---|---|---|
| Email Address | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress | Default — most SaaS apps expect email as NameID |
| Persistent | urn:oasis:names:tc:SAML:2.0:nameid-format:persistent | Opaque stable identifier — use when email may change |
| Transient | urn:oasis:names:tc:SAML:2.0:nameid-format:transient | Session-only identifier — new value each login |
| Unspecified | urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified | Passport UserId (GUID) — for custom applications |
SAML assertions are valid for 5 minutes by default (NotOnOrAfter). Ensure clock synchronization (NTP) between Passport and your SP. Clock skew > 60 seconds will cause assertion rejection. The validity window is configurable per consumer registration.
Single Logout (SLO)
Passport supports SAML 2.0 SLO. When a user logs out from any SP, Passport receives the SLO request and terminates all active SSO sessions for that user across all connected SPs. Each SP is notified via an SLO request, in parallel, before the Passport session is destroyed.
// SLO Request Flow
SP → POST /passport/saml/slo (LogoutRequest, signed)
Passport → validates signature, finds all active sessions for NameID
Passport → sends LogoutRequest to each connected SP (parallel)
Passport → destroys the Passport session
Passport → returns LogoutResponse to originating SP