SAML 2.0 Single Sign-On
SyAuth runs as a SAML 2.0 Identity Provider. Customer apps (Service Providers — Salesforce, Slack, Jira, a homegrown internal tool…) can delegate sign-in to SyAuth, receive a signed assertion back, and trust it.
Paired with our SCIM 2.0 server — which handles user and group provisioning — SAML handles authentication. Together they cover the full "SSO + Directory Sync" checklist every enterprise procurement spreadsheet contains.
The V1 implementation is deliberately small and auditable (~250 lines of SAML logic). It covers:
- SP-initiated SSO via HTTP-Redirect binding on the request and HTTP-POST on the response.
- RSA-SHA256 signed assertions (enveloped XML-DSig).
- IdP metadata endpoint for easy integration with admin consoles.
- Configurable attribute mapping per SP.
Out of V1: encrypted assertions, IdP-initiated deeplinks, Single LogOut, signed AuthnRequest verification. See the bottom of this page for the roadmap.
Configuration (one-time, per deployment)
Generate a long-lived signing keypair for the IdP:
openssl req -x509 -newkey rsa:2048 \
-keyout saml_key.pem -out saml_cert.pem \
-sha256 -days 3650 -nodes \
-subj "/CN=SyAuth IdP"
Expose the PEM strings plus entity and SSO URLs as environment variables:
| Env var | Example | Required |
|---|---|---|
SAML_IDP_ENTITY_ID | https://api.syauth.com/saml/metadata/ | yes |
SAML_IDP_SSO_URL | https://api.syauth.com/saml/sso/ | yes |
SAML_IDP_CERT_PEM | contents of saml_cert.pem | yes |
SAML_IDP_KEY_PEM | contents of saml_key.pem | yes |
SAML_IDP_LOGIN_URL | /auth/login/ (default) | no |
SyAuth will not serve SAML responses until all four are set. The metadata endpoint returns 503 with a clear message so misconfiguration is obvious.
Register a Service Provider
Open SAML SSO in the SyAuth dashboard (/security/saml) and click Register a Service Provider. Fill in:
| Field | What to put |
|---|---|
| Label | Human name like "Salesforce production" |
| SP Entity ID | The entityID from the customer app's SAML config |
| ACS URL | Where the app wants us to POST the SAML response |
| NameID Format | Usually emailAddress |
| NameID attribute | ExtsUser field — usually email |
| Attribute mapping | JSON dict: {"email": "email", "firstName": "first_name", "lastName": "last_name"} |
| Default RelayState | Optional URL to land on after sign-in |
The app's admin console will give you the first three. The attribute mapping is the most important knob — it decides what claims your customer's app sees about the user.
Supported ExtsUser field paths in mappings: email, first_name, last_name, display_name (concatenation), id.
How the SSO flow works
┌────────┐ 1. unauthenticated ┌───────────┐
│ End │ ─────────────────────▶ │ Customer │
│ User │ │ App (SP) │
└────────┘ └─────┬─────┘
▲ │
│ 6. redirect to app │ 2. build AuthnRequest, redirect
│ ▼
┌────────┐ ┌───────────────┐
│ App │ ◀─── 5. POST ACS ───── │ Browser │
│ (SP) │ │ │
└────────┘ └─────┬─────────┘
│ 3. GET /saml/sso/?SAMLRequest=…
▼
┌─────────────┐
│ SyAuth IdP │ ── 4. if not logged in,
│ │ stash + redirect to login
└─────────────┘
- User visits the customer app without a session.
- App builds a SAML
AuthnRequest, base64+deflates it, redirects the browser to SyAuth. - SyAuth parses the request, finds the
SAMLServiceProviderbyIssuer, verifies theAssertionConsumerServiceURLmatches what we have registered. - If the user is not authenticated, SyAuth stashes the request in the session and redirects to the hosted login. After a successful login the flow resumes at
/saml/sso/finish/. - SyAuth builds a signed
<Response>containing a signed<Assertion>about the user, renders an auto-submitting HTML form, and returns it to the browser. The browser POSTs to the app's ACS URL. - The app verifies the signature with the IdP cert (downloaded from
/saml/metadata/), and logs the user in.
End users see one brief redirect through SyAuth; in most cases they already have an active SyAuth session and it's invisible.
IdP metadata
GET /saml/metadata/
Returns an EntityDescriptor XML document with:
- Our entity ID.
- The signing certificate (base64 body, no PEM headers).
- Both HTTP-Redirect and HTTP-POST
SingleSignOnServiceendpoints. - Supported
NameIDFormats. WantAuthnRequestsSigned="false"— we currently accept unsigned AuthnRequests (see roadmap).
Download it and feed it into the customer app's SSO admin page in one click. This is what every modern SAML admin UI supports.
IdP-specific notes
Salesforce
- Setup → Identity → Single Sign-On Settings → New from Metadata URL.
- Paste
https://api.syauth.com/saml/metadata/. - For the SP side, Salesforce will give you an Entity ID and ACS URL — register those in the SyAuth dashboard.
Custom in-house app using python-saml / pysaml2
Point idp.metadata_url at /saml/metadata/ and accept NameID as email. Minimal SP config:
saml_settings = {
"sp": {
"entityId": "https://acme.com/saml",
"assertionConsumerService": {
"url": "https://acme.com/sso/acs",
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
},
"NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
},
"idp": {
"entityId": "https://api.syauth.com/saml/metadata/",
"singleSignOnService": {
"url": "https://api.syauth.com/saml/sso/",
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
},
"x509cert": "<contents of our signing cert>",
},
}
AWS IAM Identity Center
Import the SyAuth metadata as an external IdP; AWS generates the SP entity ID and ACS URL which you paste back into SyAuth's dashboard.
Audit events
Every SAML write or SSO attempt lands in the workspace Audit Log:
| Event | Severity | When |
|---|---|---|
saml_sp_create | info | Developer registered a new SP |
saml_sp_update | info | Developer changed SP config |
saml_sp_delete | warn | Developer deleted an SP |
saml_sso_success | info | SyAuth issued a signed assertion |
saml_sso_failure | warn | Malformed request, unknown SP, ACS URL mismatch, build error |
Every saml_sso_success includes metadata.assertion_id so you can correlate assertions with any incident reported downstream.
Security notes
- Signed assertions on by default. RSA-SHA256, exclusive canonicalisation. Downstream SPs must verify using the cert from
/saml/metadata/. - Assertion lifetime is 5 minutes with a 30-second clock-skew tolerance on
NotBefore. Short enough to resist replay, wide enough to survive small clock drift. - ACS URL is validated against the registered one. Protects against assertion-redirect open-redirect attacks where a malicious AuthnRequest asks us to POST to an attacker-controlled URL.
- Audience restriction is set to the SP's
entityId, so a captured assertion can't be replayed against a different SP. - InResponseTo is always set to the
AuthnRequest's ID. Downstream SPs that enforce it will reject assertions they didn't request. - Issuer lookup is exact-match on
SAMLServiceProvider.sp_entity_id. Unknown issuers get an explicit 400.
Developer CRUD API
All require a developer session + IsDeveloper permission. Explicit per-call workspace-membership check — no cross-tenant reads.
GET /developer/saml/sps/?workspace_id=<uuid>— listPOST /developer/saml/sps/— create (body fields:workspace_id,name,sp_entity_id,acs_url,name_id_format,name_id_attribute,sign_assertions,attribute_mapping,sp_cert_pem,default_relay_state,is_active)GET /developer/saml/sps/{id}/— readPUT /developer/saml/sps/{id}/— partial update, same fields as createDELETE /developer/saml/sps/{id}/— delete
Roadmap
Already reserved; shipping in later releases:
- Signed AuthnRequest verification. Today we ignore the signature on inbound requests. When the SP stores its signing cert in
sp_cert_pem, we'll verify. Protects against parameter tampering. - Encrypted assertions. For SPs that require
<EncryptedAssertion>instead of<Assertion>. - IdP-initiated SSO. Deep link
/saml/idp-init/?sp={id}issues an unsolicited assertion. - Single LogOut (SLO). Propagate SyAuth sign-out to every registered SP.
- Per-SP signing certs. Rotate keys per customer rather than one cert for the whole IdP.
- Conditional attribute mapping. Map different attributes depending on which group the user belongs to.
Related
- SCIM 2.0 — the provisioning side of the same enterprise story.
- Audit Log
- Token Security