SenseCrypt Docs
Concepts

SAML 2.0

SenseCrypt as a SAML 2.0 identity provider — metadata, bindings, NameID, request signatures, assertion signing and encryption, attribute release, and how the biometric ceremony fits behind SP-initiated SSO.

SenseCrypt is a SAML 2.0 identity provider (IdP). Enterprise applications that speak SAML can federate to SenseCrypt for single sign-on, and the on-device face ceremony sits behind the standard AuthnRequest/Response exchange — the service provider (SP) never sees the biometrics. From the phone's perspective the SAML ceremony is byte-identical to OIDC; only the browser-side entry and exit differ.

Each tenant is its own SAML IdP on its own hostname, with its own signing key (see Multi-tenancy).

Metadata and endpoints

Per tenant, the IdP publishes metadata and a downloadable signing certificate:

PurposeEndpointAPI reference
Metadata (application/samlmetadata+xml)GET {issuer}/v1/idp/saml/metadataref
Signing certificate (PEM)GET {issuer}/v1/idp/saml/certificateref
Single Sign-On (Redirect + POST)GET|POST {issuer}/v1/idp/saml/ssoredirect, POST
  • entityID is {issuer}/v1/idp/saml — deliberately a distinct URL under the same host so the OIDC and SAML protocol identities don't collide.
  • Single Sign-On URL is {issuer}/v1/idp/saml/sso, advertised for both the HTTP-Redirect and HTTP-POST bindings.
  • The signing key is per-tenant RSA-2048 with a self-signed X.509 certificate. During a key rotation the metadata publishes multiple <KeyDescriptor use="signing"> certificates (make-before-break), so an SP that re-fetches metadata trusts either side of the switch. The certificate endpoint accepts an optional ?kid= to download a specific published cert — including a staged one, to pre-configure an SP before activation.

Point your SP at the metadata URL, or configure the entityID, SSO URL, and certificate manually. The metadata advertises WantAuthnRequestsSigned="false" because request-signature verification is opt-in per SP (below), not IdP-global.

Sign-in flow

  1. The SP sends an AuthnRequest to /v1/idp/saml/sso (Redirect or POST binding). IdP-initiated SSO is also supported per SP (?sp=<entityID>), gated on the SP's allow_idp_initiated flag.
  2. SenseCrypt validates the request, shows the branded email-entry page, then the QR code, and the user completes the face ceremony — identical to the OIDC flow (see How SenseCrypt works).
  3. On success, SenseCrypt builds a signed SAML Response and delivers it to the SP's ACS via the HTTP-POST binding — an auto-submitting HTML form that POSTs SAMLResponse (and RelayState) to your ACS.

The full SP-initiated exchange — from the AuthnRequest through the on-device face proof to the ACS POST — looks like this:

Redirect/POST AuthnRequest (SAMLRequest, RelayState) GET|POST /v1/idp/saml/sso 302 to branded email page (opaque handoff handle ?h=) Enter email → POST (burns single-use handoff) Show sign-in QR Scan the QR with the Authenticator Signed device proof (matched against the snapshot) Authorized → fetch /v1/idp/saml/post/{session_id}?rt= GET /post/{session_id} (burns single-use token) Auto-submitting form (SAMLResponse [+ RelayState]) POST SAMLResponse to the ACS (HTTP-POST binding) Decode + parse AuthnRequest; resolve SP by Issuer entityID;verify request signature (opt-in per SP); validate ACS againstthe acs_urls allow-list; validate NameID Format Gate the user on the SP's attached groups; snapshot theface-token onto a protocol='saml' session; redirect to the QR page Face proof on device — no biometric data leaves the phone Re-run the access gate (TOCTOU); release attached-scope claims;build the assertion — always signed (sign-then-encrypt if configured) Verify the signature → user signed in Service Provider Browser SenseCrypt IdP Phone / Authenticator

Sign-in for a SAML SP is gated by the SP's attached groups, exactly like an OIDC app: an SP with zero attached groups admits nobody (default-closed). See Authorization.

Assertion Consumer Service (ACS) validation

A requested ACS URL must be on the SP's registered acs_urls allow-list — this is the SAML analog of OIDC's redirect_uri validation, and a mismatch is refused. If the AuthnRequest omits the ACS, the SP's first registered ACS is used.

Request signatures

Verifying the SP's AuthnRequest signature is opt-in per SP: it is enforced only once you register the SP's signing certificate (sp_signing_cert_pem). Both bindings are supported:

  • Redirect binding verifies the detached signature over the original percent-encoded query octets (SAMLRequest=…&RelayState=…&SigAlg=…), per the SAML Bindings spec.
  • POST binding verifies the enveloped XML-DSig.

Verification always pins to the configured certificate; any <KeyInfo> certificate embedded in the request is ignored. RSA keys are required; accepted SigAlg values are rsa-sha1, rsa-sha256, rsa-sha384, rsa-sha512.

NameID

  • Request the urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress NameID format to receive the user's email as the NameID.
  • Any other format (persistent, transient, unspecified) yields a stable, opaque identifier for the user (the same per-tenant subject id, not a raw database id).
  • A NameID policy requesting a specific format that doesn't match the SP's configured format is rejected with a SAML InvalidNameIDPolicy status; an absent or "unspecified" policy falls back to the SP's configured format.

Signing and encryption

The assertion crypto is RSA-based and standards-aligned:

  • The assertion is always signed — RSA-SHA256 with SHA-256 digests and exclusive C14N. The outer <Response> is additionally signed when the SP has want_response_signed set. There is an invariant that a Response can never be wholly unsigned: if the response isn't signed (or the assertion is encrypted), assertion signing is force-enabled, so there is always something verifiable.
  • Assertion encryption is optional, enabled by registering the SP's encryption certificate (encryption_cert_pem). SenseCrypt does sign-then-encrypt into an <EncryptedAssertion>:
    • Data encryption: AES-256-CBC (http://www.w3.org/2001/04/xmlenc#aes256-cbc), with a random 16-byte IV and PKCS#7 padding (integrity comes from the enclosed signature).
    • Key transport: RSA-OAEP with SHA-256 + MGF1-SHA256 (http://www.w3.org/2009/xmlenc11#rsa-oaep).
    • Note this is CBC, not GCM.

The assertion carries a Bearer SubjectConfirmation (with Recipient = ACS and InResponseTo for SP-initiated requests), an AudienceRestriction of the SP entityID, and a validity window of NotBefore = issue − 30 s to NotOnOrAfter = issue + 300 s (5 minutes). The default AuthnContextClassRef is urn:oasis:names:tc:SAML:2.0:ac:classes:Biometric — the SAML twin of the OIDC acr — and is per-SP overridable to any URI.

Attribute release

Attribute release is gated by the scopes attached to the SP, then renamed by the SP's attribute map:

  1. A claim is released only when a scope attached to the SP releases it and the user has a value.
  2. The SP's attribute_map renames released claims onto your SAML attribute names. The map can only rename — it can never release an attribute that no attached scope allows. A mapping entry for an unreleased claim is inert and silently dropped, not an error.
  3. The NameFormat per attribute is configurable via attribute_name_format: unspecified (the NameFormat attribute is omitted entirely), basic (…attrname-format:basic), or uri (…attrname-format:uri — the last is what Entra ID expects). Multi-valued claims render as repeated <AttributeValue> elements.

See Authorization for how scopes and attributes are modeled.

Per-SP configuration summary

The SP registration controls the crypto and behavior above through these fields:

FieldEffect
acs_urlsACS allow-list (list of {url, binding}) — the redirect_uri analog.
sp_signing_cert_pemWhen set, AuthnRequest signatures are verified (opt-in). RSA only.
encryption_cert_pemWhen set, assertions are encrypted (sign-then-encrypt). RSA only.
want_assertions_signedSign the assertion (default on; force-enabled when needed).
want_response_signedSign the outer <Response> as well.
allow_idp_initiatedPermit IdP-initiated SSO (?sp=<entityID>).
name_id_formatThe SP's default NameID format.
attribute_mapRenames released claims onto SAML attribute names (rename only).
attribute_name_formatunspecified | basic | uri.
authn_context_class_refThe asserted AuthnContext (default …:Biometric).

What is not supported

Verified by absence in the implementation — do not expect these:

  • Single Logout (SLO) is not implemented. There is no SingleLogoutService in the metadata and no LogoutRequest/LogoutResponse handling — there is no IdP-side SSO session to propagate a logout from.
  • HTTP-Artifact binding is not supported. AuthnRequests accept Redirect and POST; Response delivery is POST-only.
  • Request-signature verification and assertion encryption require RSA SP certificates (no ECDSA).
  • Only Issuer / ID / ACS URL / NameIDPolicy Format are read from the AuthnRequest; <Extensions>, ForceAuthn/IsPassive, and RequestedAuthnContext are ignored.

Gotchas

  • The attribute map renames; it doesn't release. If an attribute isn't coming through, check that a scope releasing it is attached to the SP — the map alone won't surface it.
  • Use the uri NameFormat for Entra ID. Entra expects attrname-format:uri; unspecified omits the format entirely.
  • No SLO. Sign the user out on your side by clearing your own session; there is no SAML logout to call.
  • Encryption is CBC, and requires an RSA encryption cert. Register encryption_cert_pem (RSA) to enable it; an ECDSA cert won't work.

Set it up

Follow the SAML SSO integration guide to register your SP and configure attribute mapping. Endpoint detail is in the SAML API reference.

Learn more

On this page