Configuring SAML Applications for Enterprise SSO in Logto: The Complete Technical Guide
Logto implements SAML-based enterprise SSO through a dedicated application type that stores configuration across three linked database records—application metadata, SAML-specific settings, and encrypted X.509 secrets—while exposing REST endpoints for SP metadata exchange and assertion handling.
Configuring SAML applications for enterprise SSO in Logto requires navigating a multi-layered architecture that separates generic application data from protocol-specific configuration and cryptographic secrets. The logto-io/logto repository provides a complete implementation spanning schema validation guards, core libraries, and REST API endpoints to handle both SP-initiated and IdP-initiated authentication flows.
Understanding the SAML Application Data Model
Logto treats SAML integrations as a distinct application type consisting of three interconnected storage layers:
- Application entry – Stores common fields including
name,description, andcustomData(defined in theApplicationsschema) - SAML configuration – Contains
entityId,acsUrl,attributeMapping,encryptionsettings, andnameIdFormat(managed inSamlApplicationConfigs) - SAML secrets – Houses X.509 certificates and private keys, exposing only the public SHA-256 fingerprint while keeping private keys encrypted (see
SamlApplicationSecrets)
These records are wired together through validation guards defined in packages/schemas/src/types/saml-application.ts. The samlApplicationCreateGuard enforces that attributeMapping and spMetadata cannot be omitted separately, ensuring data integrity during creation:
// packages/schemas/src/types/saml-application.ts
export const samlApplicationCreateGuard = applicationCreateGuard
.pick({ name: true, description: true, customData: true })
.merge(samlAppConfigGuard.partial())
.extend({ nameIdFormat: nameIdFormatGuard.optional().default(NameIdFormat.Persistent) });
The SamlApplicationResponse type merges generic Applications fields with SAML-specific configuration, producing the unified API response shape returned by Logto's endpoints.
Core Architecture and Source Files
The SAML implementation spans four architectural layers:
| Component | Responsibility | Key Source File |
|---|---|---|
| Schema definitions | Zod guards for validation and response shapes | packages/schemas/src/types/saml-application.ts |
| Core library | High-level CRUD operations and session management | packages/core/src/libraries/saml-application/saml-applications.ts |
| REST routes | API endpoints for metadata and assertions | packages/core/src/routes/saml-application/index.ts |
| Utilities | Callback URL generation for IdP-initiated flows | packages/core/src/saml-application/SamlApplication/utils.ts |
The core library is instantiated in packages/core/src/tenants/Libraries.ts and injected into request contexts, providing a clean separation between data access and HTTP transport concerns.
API Endpoints for SAML Lifecycle Management
The router in packages/core/src/routes/saml-application/index.ts exposes the complete SAML application lifecycle through the following endpoints:
| Method | Path | Purpose |
|---|---|---|
POST |
/saml-applications |
Create a new SAML application |
GET |
/saml-applications/:id |
Retrieve application details including SAML config |
GET |
/saml-applications/:id/metadata |
Return SP metadata XML for IdP consumption |
POST |
/saml-applications/:id/callback |
Assertion consumer endpoint for SP and IdP flows |
PATCH |
/saml-applications/:id |
Update existing SAML configuration |
DELETE |
/saml-applications/:id |
Remove the SAML application |
Creating a SAML Application
To provision a new SAML application, send a POST request to the /saml-applications endpoint with the required configuration:
curl -X POST https://<tenant>.logto.io/api/saml-applications \
-H "Authorization: Bearer <admin-access-token>" \
-H "Content-Type: application/json" \
-d '{
"name": "My SAML App",
"description": "Enterprise SSO integration",
"entityId": "https://my-company.com/saml-sp",
"acsUrl": "https://my-company.com/saml-acs",
"attributeMapping": {
"email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
"name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
},
"encryption": {
"enabled": false
},
"nameIdFormat": "persistent"
}'
The response conforms to the SamlApplicationResponse type, returning the merged application data and SAML configuration.
Retrieving SP Metadata
After creation, retrieve the Service Provider metadata XML that your Identity Provider requires:
curl -X GET https://<tenant>.logto.io/api/saml-applications/<app-id>/metadata \
-H "Authorization: Bearer <admin-access-token>"
This returns an XML document similar to:
<EntityDescriptor entityID="https://my-company.com/saml-sp" ...>
<SPSSODescriptor WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://my-company.com/saml-acs" index="1"/>
...
</SPSSODescriptor>
</EntityDescriptor>
Import this XML into your IdP's SAML SP metadata configuration to establish trust.
Handling IdP-Initiated SSO
For IdP-initiated flows, the Identity Provider POSTs SAML assertions to Logto's callback URL. This URL is generated by the getSamlAppCallbackUrl function in packages/core/src/saml-application/SamlApplication/utils.ts and follows the pattern:
https://<tenant>.logto.io/api/saml-applications/<app-id>/callback
When handling assertions programmatically, forward the SAML response to this endpoint:
import fetch from 'node-fetch';
await fetch(`https://<tenant>.logto.io/api/saml-applications/${appId}/callback`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
SAMLResponse: '<base64-encoded-assertion>',
RelayState: 'optional-state'
})
});
Logto validates the assertion, decrypts the content if encryption is enabled, extracts the NameID according to the configured nameIdFormat, and establishes an authenticated session.
Certificate Rotation and Secret Management
SAML signing certificates are managed through the SamlApplicationSecrets table. To rotate certificates without service interruption:
curl -X POST https://<tenant>.logto.io/api/saml-applications/<app-id>/secrets \
-H "Authorization: Bearer <admin-access-token>" \
-H "Content-Type: application/json" \
-d '{"lifeSpanInYears": 5}'
The API returns the new public fingerprint (SHA-256 hash) but never exposes the private key, maintaining security boundaries consistent with the implementation in packages/core/src/libraries/saml-application/saml-applications.ts.
Summary
Configuring SAML applications for enterprise SSO in Logto follows a structured three-phase approach:
- Data modeling relies on three linked records (application, config, secrets) validated through Zod guards in
packages/schemas/src/types/saml-application.ts - Metadata exchange uses the
/saml-applications/:id/metadataendpoint to generate SP metadata for IdP consumption - Assertion handling occurs through the
/saml-applications/:id/callbackendpoint, supporting both SP-initiated and IdP-initiated flows with automatic decryption and session creation
The architecture ensures that sensitive cryptographic material remains encrypted while exposing only necessary public certificates and metadata endpoints.
Frequently Asked Questions
How does Logto store SAML application credentials securely?
Logto stores X.509 certificates and private keys in the SamlApplicationSecrets table, exposing only the SHA-256 fingerprint through the API while keeping private keys encrypted at rest. When you rotate certificates via the /secrets endpoint, the system generates new key pairs but only returns the public fingerprint, ensuring private keys never travel over the network or appear in logs.
What is the difference between SP-initiated and IdP-initiated SSO in Logto?
SP-initiated SSO begins when a user clicks "Log in with SAML" on your application, triggering Logto to send an authentication request to the IdP. IdP-initiated SSO occurs when a user logs into the IdP directly and selects your application from their dashboard, causing the IdP to POST a SAML assertion to Logto's callback URL generated by getSamlAppCallbackUrl in packages/core/src/saml-application/SamlApplication/utils.ts. Both flows converge at the /callback endpoint, but IdP-initiated requires the IdP to know the specific callback URL format.
Can I configure attribute mapping for SAML assertions?
Yes, the attributeMapping field in the SAML application configuration allows you to map IdP claim URIs to Logto user attributes. When creating the application, specify mappings such as "email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" in the request body. Logto extracts these attributes from the SAML assertion during callback processing and associates them with the authenticated session according to the mapping defined in SamlApplicationConfigs.
Where can I find integration tests for the SAML application API?
The complete request/response flow is demonstrated in packages/integration-tests/src/tests/api/application/saml-application.test.ts, which validates the CRUD operations, metadata generation, and assertion handling endpoints. These tests serve as executable examples of how the /saml-applications, /metadata, and /callback endpoints interact during real-world SSO scenarios.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →