SAML 2.0 single sign-on

Updated

Available on Business and Enterprise plans. Kryptic acts as a SAML 2.0 service provider, so your identity provider stays the source of truth for who can sign in.

Connect your identity provider

1. Give your IdP administrator the service provider metadata.

https:///saml/metadata

It declares our entity id, the assertion consumer service URL, and that we require signed assertions. We do not sign AuthnRequests, so no key exchange is needed in that direction.

2. Paste the IdP's metadata into Kryptic and claim your email domain.

curl -X POST https://<your-api-host>/api/enterprise/idp/saml \
  -H "Authorization: Bearer $OWNER_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "domain": "acme.com", "provider": "Okta", "metadataXml": "<EntityDescriptor …>" }'

The metadata is parsed immediately, so a bad document is rejected while you are still looking at it rather than at the first login attempt. The response includes the signing certificate's expiry date - watch it.

3. Users sign in.

https:///saml/login?domain=acme.com

The first successful sign-in provisions the user as a Developer. Elevate roles inside Kryptic, not in the IdP.

What we verify before trusting an assertion

Every item below is an authentication bypass if it is missing. Each has an automated test that constructs the actual attack.

CheckAttack it closes
Exactly one signature, verified against the certificate from your metadataForged or attacker-signed assertions
The assertion used is the one the signature covers, and the document has exactly one assertionXML signature wrapping
SHA-1 and MD5 refusedAlgorithm downgrade
InResponseTo matches a login we startedReplay of a captured assertion
Destination is our ACS URLAssertion minted for a different service provider
Audience is our entity idSame
Issuer is your configured IdPAssertion from an unrelated IdP
Conditions within NotBefore/NotOnOrAfter (±3 min skew)Expired assertion reuse
Status is Success before anything else is readTreating a failed login as a success
DTDs and external entities disabledXXE

Rejections are audit-logged as auth.saml_rejected with the reason, so a misconfiguration is diagnosable without turning on debug logging.

Disconnecting

curl -X DELETE https://<your-api-host>/api/enterprise/idp/saml/{id} \
  -H "Authorization: Bearer $OWNER_TOKEN"

/saml/login immediately stops serving that domain. Existing sessions continue until they expire - revoke them from Members if you need access to stop now.

Next

Pair SSO with SCIM provisioning so joiners and leavers are handled automatically rather than by hand.