Skip to content

Concepts

What is SAML?

SAML is the protocol most enterprises still use to let their staff sign in to software they did not write. It is old, verbose and XML-based, and it is also the thing standing between you and a large customer — so it is worth understanding rather than merely surviving.

The idea in one paragraph

SAML — Security Assertion Markup Language — lets one system vouch for a person to another system. The customer's identity provider knows who its staff are; your application does not, and would rather not. Instead of holding their passwords, you accept a signed statement from the provider saying who just authenticated and when.

That signed statement is called an assertion. It is an XML document, signed with a certificate you were given in advance, and it is the entire trust relationship. If the signature checks out against the certificate you already hold, the claims inside it are true as far as your application is concerned.

Everything else in SAML — the redirects, the encoded parameters, the metadata files — exists to move that one document from the provider to you and to agree in advance on how it will be signed.

The three parties

SAML documentation is dense partly because it names everything. Three terms carry most of the meaning, and the rest can be looked up when you meet them.

TermWho it isIn practice
Identity provider (IdP)The customer's directory or identity platformHolds the accounts and performs the actual authentication
Service provider (SP)Your applicationAccepts the assertion and creates a local session
PrincipalThe person signing inIdentified in the assertion by a name ID

What actually happens

The common case is service-provider-initiated: somebody starts at your sign-in page. The alternative, identity-provider-initiated, starts from a tile in the customer's application launcher and skips the first two steps.

  1. 1The person enters a work email at your sign-in page, or picks their workspace.
  2. 2You look up which connection that domain belongs to and redirect the browser to the identity provider with an authentication request.
  3. 3The identity provider authenticates them however it likes — password, MFA, a device certificate, a session it already had.
  4. 4It POSTs a signed assertion back to your assertion consumer service URL.
  5. 5You verify the signature, check the audience and the timestamps, read the attributes and create your own session.

With Paycux, steps two, four and five happen inside the platform. Your application redirects to an authorization URL and receives a normalised profile, so no XML parsing or certificate handling lands in your codebase.

The values you exchange

Setting up a connection is an exchange of five or six values. Most failed first attempts are one of them being wrong, so it helps to know what each is for.

ValueDirectionWhat it is for
ACS URLYou give to the IdPWhere the assertion is POSTed. Also called the reply URL.
Entity IDYou give to the IdPA stable identifier for your application, used as the audience.
Sign-on URLIdP gives to youWhere the browser is sent to start authentication.
X.509 certificateIdP gives to youThe public key the assertion signature is verified against.
Name ID formatAgreedWhat the subject identifier will contain, usually an email address.
Attribute statementsAgreedThe extra claims sent alongside: name, groups, employee ID.

Attributes and mapping

An assertion carries attributes whose names are chosen by whoever configured the provider. One customer sends a claim called mail, the next sends a long URN, and a third sends nothing but a name ID. Mapping is the work of deciding which incoming claim becomes which field on your user.

Paycux normalises the common attributes before your callback runs, so the profile you receive has the same shape regardless of the provider. The mapping below is what a normalised profile looks like.

profile.json
1{
2 "id": "prof_01HQZX8N4T",
3 "connectionId": "conn_01HQZX8N4T",
4 "connectionType": "SAML",
5 "organizationId": "org_01HQZX8N4T",
6 "idpId": "00u1a2b3c4d5e6f7g8h9",
7 "email": "avery@foo-corp.example",
8 "firstName": "Avery",
9 "lastName": "Lindqvist",
10 "groups": ["Engineering", "All Staff"],
11 "rawAttributes": {
12 "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": "avery@foo-corp.example"
13 }
14}

Choosing a stable identifier

The single most consequential decision in a SAML integration is what you key your user records on. Email looks obvious and is wrong: people change surnames, companies rebrand domains, and an address that identified one person in March can be reassigned to another by December.

Use the provider's own subject identifier — idpId in a normalised profile — as the key, and treat email as a mutable attribute you keep up to date. Doing this on day one costs nothing; doing it after a customer has renamed a domain is a data migration.

If the identifier changes between two sign-ins by the same person, the provider is sending a transient name ID. Ask for a persistent format, or the emailAddress format if the customer's addresses are genuinely stable.

Where it goes wrong

SAML failures are almost always configuration, not code. These five account for the overwhelming majority of first-attempt problems.

  • ACS URL mismatch — the provider posts to a slightly different URL than the one registered, often a trailing slash or http instead of https.
  • Audience mismatch — the entity ID configured at the provider is not the one your connection expects, so a valid assertion is refused.
  • Clock skew — assertions carry a narrow validity window, and a server minutes out of step rejects everything.
  • Expired certificate — the signing certificate rotated at the provider and nobody told you. This breaks a working integration overnight.
  • Missing attributes — the connection works, but the profile arrives with no name because the provider was never asked to send one.