SAML Flow

Set up SAML-based SSO: Business Health acts as a SAML Service Provider, federating with your Identity Provider to authenticate users and issue a JWT for widgets or the Dashboard.

Use SAML when you already run a SAML 2.0 Identity Provider (IdP) — for your platform's own employee or customer SSO, for example — and want Business Health to federate with it directly, instead of building a signed server-to-server call or a callback endpoint of your own. This fits best when Business Health is embedded as its own page — the full Dashboard, or a single widget that's the main content of its page. See why below.

Business Health acts as the SAML Service Provider (SP): it redirects the user's browser to your IdP, consumes the signed assertion your IdP returns, and uses it to establish the user's identity.

🚧

Best Fit: Dashboard or a Standalone Widget Page

Like Get Token, this flow has both a redirect-based endpoint (Dashboard) and a JSON endpoint (widgets) — but getting there means a full browser redirect through your IdP, which fits naturally when Business Health is the page the user is on. (Even when the user already has a live IdP session and isn't prompted for credentials again, that redirect still happens — it's just quick.) Containing that redirect to a single widget on a page full of other content means running the whole handshake inside that widget's own iframe, and some IdPs restrict framing (see the callout under Use the Result below).

For a widget that renders inline alongside other content with no visible redirect, Get Token Flow is the better match — your backend asserts identity directly to Business Health, with no browser hop at all. SAML is the better fit when Business Health is its own destination page, or when you'd rather not write any backend integration code at all.

How It Works

sequenceDiagram
    participant Page as Browser
    participant BH as Business Health
    participant IdP as Your SAML IdP

    Page->>BH: GET /api/auth-service/saml/login
    Note over BH: Build & sign AuthnRequest
    BH-->>Page: Redirect to your IdP
    Page->>IdP: AuthnRequest
    Note over IdP: User authenticates
    IdP-->>Page: SAML Response (signed assertion)
    Page->>BH: POST /api/auth-service/saml/login (or .../get-token)<br/>SAMLResponse
    Note over BH: Validate assertion,<br/>extract CUSTOMER/COMPANY claims,<br/>create/update user & company,<br/>generate JWT
    BH-->>Page: Redirect with JWT (saml/login)<br/>or just the JWT (saml/get-token)

1. Request SAML Login

Send the user's browser to Business Health's SAML login endpoint — either by linking there directly from your platform, or as part of your own navigation:

GET {baseUrl}/api/auth-service/saml/login

2. Build & Sign AuthnRequest

Business Health builds and signs an AuthnRequest, using the issuer and algorithm configured in your tenant's SamlIssuer and SamlSignatureAlgorithm system settings. It then redirects the browser to your IdP's single sign-on endpoint — resolved from your IdP's metadata (the URL configured in the SamlIdPMetadata system setting) or, if that's not available, the fallback URL configured in the SamlSingleSignOnDestination system setting. The user visibly leaves your platform's domain at this point and lands on your IdP's own login page — whatever that looks like for your organization.

3. IdP Authenticates User

Your IdP authenticates the user there (credentials, MFA, or whatever your IdP normally requires), then posts a SAML Response back to Business Health as a signed assertion. This typically happens via a self-submitting HTML form your IdP returns to the browser, which submits itself automatically — from the user's perspective it looks like a brief redirect, not a form they fill out themselves.

4. Validate Assertion

Business Health validates the assertion's signature, using your IdP's validation certificate as configured in your tenant's SamlSignatureValidationCertificate system setting; checks its audience against the values configured in your tenant's SamlIssuer and SAMLAllowedAudiences system settings; and, if the assertion is encrypted, decrypts it using the certificate configured in the SamlDecryptionCertificate system setting. It then reads the user and company details out of two custom attribute statements in the assertion:

  • CUSTOMER — a JSON string matching the SSO Payload's user-level fields (name, email, externalId, etc.)
  • COMPANY — a JSON string matching the SSO Payload's accountData shape

See SSO Payload for the full schema both claims need to follow.

📘

Same Matching, Same Schema

This is the same underlying schema used by Get Token and Component Auth — only how the data arrives is different. See the next step for how it's matched against existing records.

5. Business Health Auth

Business Health creates or updates the user and company from the claims — matching against existing records using externalId and/or email — and generates a JWT. See How Business Health Matches Users & Companies in Widget & Dashboard Integration for exactly how that matching, creation, and linking works (this flow shares that behavior with Component Auth).

🚧

Omitting firstName/lastName on a Later Login Clears Them

Unlike most other fields, firstName and lastName aren't preserved if a later login's claim leaves them blank — they'll be cleared, even though the combined name field is protected (it falls back to whatever's already on record if omitted). If you want to update just one of firstName/lastName, resend both together.

6. Use the Result

Which result you get back depends on which endpoint you register as your IdP's Assertion Consumer Service (ACS) URL when you set up the federation — not something chosen per login the way Get Token's two endpoints are, since the login-initiation request (step 1) takes no parameters to select one.

For the Dashboard, register {baseUrl}/api/auth-service/saml/login as your ACS URL. The simplest way to embed it: point an iframe directly at the SAML login endpoint, and let the entire redirect chain — through your IdP and back — play out inside it:

<iframe src="{baseUrl}/api/auth-service/saml/login"></iframe>

Unlike Get Token's Dashboard Login, your backend never receives or handles a URL here — Business Health's final response is a redirect straight to {StaticHost}/#/msbredirect?token=... (the same destination Get Token's redirect lands on), except it's the browser itself, inside the iframe, that's redirected there directly.

🚧

Your IdP's Login Page Renders Inside That Iframe Too

Framing the whole handshake this way means your IdP's own login page loads inside the iframe as well, which works well when your IdP allows framing. If your IdP's policy restricts this (for example, via X-Frame-Options or frame-ancestors), drive the handshake at the top level instead, landing the user on a full-page Dashboard. Confirm your IdP's framing policy before committing to this approach.

For individual widgets, register {baseUrl}/api/auth-service/saml/get-token as your ACS URL instead. Once Business Health responds with the JWT as JSON, pass it to widgets via their token property — same as Get Token.

Full parameters, request/response bodies, and an interactive "Try it" console are in the API Reference.

Signing Out

Business Health supports SAML Single Logout (SLO), which ends the user's federated session at your IdP, so a logout at your IdP (or at another app relying on the same IdP session) correctly reaches Business Health too, and vice versa.

SLO is a browser-redirect protocol, not a backend webhook — the only way your IdP can notify Business Health is by sending the user's browser through the endpoints below. That matters for an embedded integration: the IdP-initiated case runs as a top-level browser redirect, not something contained inside a widget or iframe (the one exception is noted below).

Responding to a Logout Your IdP Initiates

When the user logs out at your IdP — or at another app sharing the same IdP session — your IdP sends a SAML LogoutRequest to:

GET|POST {baseUrl}/api/auth-service/saml/single-logout

Register this as Business Health's Single Logout Service endpoint on your IdP side. Business Health validates the request and replies with a SAML LogoutResponse, completing its part of the handshake so your IdP — and anything else participating in the broader federated logout — can consider it done.

Because this exchange runs in the browser's top-level tab, it isn't something a widget or Dashboard embedded on your page visibly participates in: by the time it happens, the browser has already left your page to process it, and only returns to wherever the logout flow is configured to land.

Starting a Logout From Business Health

If your platform wants Business Health to proactively end the user's session at your IdP too — for example, a "log out" action inside an embedded Dashboard — send the browser to GET /api/auth-service/saml/logged-out, which builds and sends a SAML LogoutRequest to your IdP. Your IdP's reply completes the handshake on its own terms, per your IdP's SAML metadata.

If the Dashboard is embedded in an iframe, this specific round-trip — unlike the IdP-initiated case above — can stay contained within that iframe, same as logging in: only if your IdP allows itself to be framed.

Why Participate in SLO at All?

Since this flow's token isn't persisted in the browser anyway (see Token Lifecycle), there's nothing for Business Health to locally clean up by participating in SLO — its value is entirely about playing its part in the broader federated logout correctly, since your IdP (and any other apps relying on the same session) depend on Business Health acknowledging the handshake. If you also want Business Health's own session ended, call GET /api/AuthService/Logout separately.

Token Lifecycle

This flow produces its JWT the exact same way Get Token does, so the same behavior applies to storage, refetching, and refresh:

  • Storage: the resulting token isn't persisted by widgets — it's held in memory for the current page load only (via the redirect URL for the Dashboard, or the token property for widgets). It isn't written to localStorage, sessionStorage, or a cookie.
  • On reload: nothing survives a full page reload. Reloading means sending the browser through GET /api/auth-service/saml/login again — a full round-trip through your IdP, unless your IdP maintains its own session and can respond without re-prompting the user (that's between the browser and your IdP; Business Health doesn't control it).
  • Revocation: since the token isn't persisted in the browser, there's typically nothing to revoke — it stops being usable the moment the page is gone. If you want to end a Business Health session explicitly before its natural expiry — independent of SLO above, which addresses your IdP-level session, not this one — call GET /api/AuthService/Logout.
  • Refresh: you don't normally need to worry about token expiration here either — its lifetime is typically configured to comfortably outlast a normal page session, and a reload just re-runs the login anyway, producing a fresh token. If you want full control over this, decode the token and check its exp claim yourself, and send the user through the login endpoint again ahead of time if you need to extend a long-running page without a reload.

Business Health Settings

Before this flow works, your Business Health tenant needs to be configured per-tenant with the following system settings:

System SettingPurpose
SamlIssuerBusiness Health's own SAML entity ID for this tenant — also automatically included as an allowed audience for incoming assertions.
SamlSignatureAlgorithmAlgorithm Business Health uses to sign its outgoing AuthnRequests.
SAMLAllowedAudiencesAdditional allowed audience values for incoming assertions, beyond SamlIssuer itself (semicolon-separated).
SamlIdPMetadataURL of your IdP's SAML metadata — Business Health fetches your SSO and SLO endpoints from here automatically.
SamlSingleSignOnDestinationFallback SSO endpoint URL, used only if your IdP's metadata doesn't provide one.
SamlSingleLogoutDestinationFallback SLO endpoint URL, used only if your IdP's metadata doesn't provide one.
SamlSignatureValidationCertificateYour IdP's public certificate, used to validate the signature on the assertions and responses it sends.
SamlDecryptionCertificate / SamlDecryptionCertificatePasswordBusiness Health's own certificate and its password, used to decrypt assertions — configured even if your IdP doesn't encrypt them, since it's loaded unconditionally.

Did this page help you?