Practice: SAML 2.0 single sign-on

Generated by Claude (Fable 5.1) by hand from the identity and integration ops spike, Scout learning center on 2026-10-14.

Main tool: Keycloak as IdP and node-saml as SP · A SAML integration has two sides and the free way to hold both is Keycloak as the identity provider and a small node-saml service provider you can read in full: every option of the SP (signatures wanted, audience, clock skew, InResponseTo) is one line, every IdP field is a console switch, and a scripted browser lets you replay and tamper on purpose. The learning center ran this path end to end against Keycloak 26.4 and node-saml 5, and the step outcomes are its outputs. · Alternatives: python3-saml is the Python SP toolkit and its settings file has the same fields, but it needs libxmlsec1 from the system package manager (a global install, so reader-only here); pysaml2 can play both SP and IdP in tests; Keycloak can also act as the SP through identity brokering against a second realm; a free Okta or Entra tenant gives a real customer-side IdP, covered in the Okta and Entra lesson; samltool.com decodes messages when you have no script.

Every step links into the tool's own documentation; links were checked on 2026-10-14 · version 1

Setup (one time)

  • 1. Start Keycloak 26.4 in Docker on 127.0.0.1:18080 (as in the OpenID Connect practice path) with a realm and a user alice (alice@example.test) in a group integration-engineers.

    Keycloak is a full SAML 2.0 IdP out of the box, which is what makes a local round trip possible without a vendor account.

    Explained in: Keycloak Server Administration Guide (www.keycloak.org), checked 2026-10-14

    Done when: The realm's SAML IdP descriptor at <realm>/protocol/saml/descriptor answers 200 with XML that contains an X509Certificate element.

  • 2. In a scratch folder, npm install express and @node-saml/node-saml (no global install) and save the lesson's 40-line service provider as sp.js, reading the IdP certificate PEM from a file you extract in step 1. No-Docker alternative for the IdP: samlify (Node) or pysaml2 (Python) as a scripted IdP, since node-saml is an SP library only; python3-saml as the SP needs libxmlsec1 from the system package manager and is reader-only here.

    node-saml is pure JavaScript, so the SP runs anywhere Node runs; its options list doubles as the SP validation checklist.

    Explained in: node-saml README (github.com), checked 2026-10-14

    Done when: node sp.js prints that the SP listens on 127.0.0.1:18082 and GET /saml/metadata returns an EntityDescriptor.

  • 3. Create a Python virtual environment with requests for the scripted browser (or use a real browser with the SAML-tracer add-on and read the messages there).

    Either tool shows the AuthnRequest and the Response; the script also lets you replay and tamper on purpose.

    Explained in: SAML-tracer (Firefox add-on) (addons.mozilla.org), checked 2026-10-14

    Done when: python -c 'import requests' exits 0, or the SAML-tracer icon appears in the browser toolbar.

Steps

  • 1. Fetch the realm's SAML descriptor and extract the signing certificate (the X509Certificate text, wrapped as a PEM) to a file; note the IdP's entityID and its SingleSignOnService URL for the HTTP-Redirect and HTTP-POST bindings.

    This is 'their metadata' in every customer exchange; reading it by hand once makes the console fields obvious later.

    Explained in: OASIS: Security Assertion Markup Language (SAML) V2.0 Technical Overview (docs.oasis-open.org), checked 2026-10-14

    Done when: You have a PEM file and can name the IdP entity ID and the two SSO URLs.

  • 2. Start the SP and open its /saml/metadata; read your entityID, the AssertionConsumerService URL and binding, the NameIDFormat and whether it declares WantAssertionsSigned.

    This is 'your metadata'; the values here and the IdP's client registration must agree exactly.

    Explained in: node-saml README (github.com), checked 2026-10-14

    Done when: You can list the four values a customer's IdP administrator will ask you for.

  • 3. Register the SP in Keycloak as a SAML client: client id equal to the SP's entityID (its metadata URL), valid redirect URI and assertion consumer POST URL equal to the ACS, NameID format email with force on, assertions and documents signed with RSA-SHA256, client signature off, force POST binding on, plus an email property mapper and a group membership mapper (single attribute, no full path).

    Registering an SP in the customer's IdP is the integration; Keycloak's fields map one to one onto Okta's and Entra's.

    Explained in: Keycloak Server Administration Guide (www.keycloak.org), checked 2026-10-14

    Done when: The client saves without error and its 'Installation' or settings page shows the ACS and NameID format you set.

  • 4. Start an SP-initiated login (GET /login), capture the redirect, and inflate the SAMLRequest: name the AuthnRequest's ID, Destination, AssertionConsumerServiceURL, ProtocolBinding and Issuer, and the RelayState.

    Reading the request is the first half of every SAML trace; the Entra page says what an IdP reads from each element.

    Explained in: Microsoft Entra: Single sign-on SAML protocol (learn.microsoft.com), checked 2026-10-14

    Done when: You have printed the AuthnRequest XML and the five values; the Destination equals the IdP's SSO URL from step 1.

  • 5. Log in as alice; capture the auto-post form, base64-decode the SAMLResponse and read it: the StatusCode, the NameID and its format, the Audience, the number of Signature elements, the attribute names, and the Conditions' NotBefore and NotOnOrAfter.

    A decoded response next to the claims reference is the fastest education in SAML there is; this is what you will decode from a customer's tracer export.

    Explained in: Microsoft Entra: SAML token claims reference (learn.microsoft.com), checked 2026-10-14

    Done when: The status is Success, the NameID is alice@example.test, the Audience is your entityID, email and groups are among the attributes, and at least two signatures are present.

  • 6. POST the captured SAMLResponse and RelayState to the ACS.

    A genuine response accepted after every validation is the happy path; the next two steps prove the validations are real.

    Explained in: OWASP SAML Security Cheat Sheet (cheatsheetseries.owasp.org), checked 2026-10-14

    Done when: The SP answers 200 with ok true, the NameID, the email and the groups attribute; the learning center's run produced exactly that.

  • 7. POST the same SAMLResponse to the ACS a second time.

    Replay is the cheapest attack on a bearer document; the request binding is the defence, and it also explains why the next step needs a fresh login.

    Explained in: OWASP SAML Security Cheat Sheet (cheatsheetseries.owasp.org), checked 2026-10-14

    Done when: The SP answers 400 with an InResponseTo error ('InResponseTo is not valid'), and you can explain which cache the SP consulted.

  • 8. Log in again to get a fresh response, replace alice@example.test with mallory@example.test inside the signed assertion, re-encode and POST it.

    The signature covers the assertion bytes; a changed NameID is a changed document. This is the test to run against any SP you are asked to review.

    Explained in: OWASP SAML Security Cheat Sheet (cheatsheetseries.owasp.org), checked 2026-10-14

    Done when: The SP answers 400 with a signature error ('Invalid document signature').

  • 9. Switch the SP to wantAssertionsSigned only (response signature not required) and in Keycloak turn off 'Sign documents' but keep 'Sign assertions'; repeat the login, the replay and the tampering. (Read, not run by the learning center.)

    Customers' IdPs differ in what they sign; an SP that insists on both will reject some of them, and this step shows what the weaker setting still protects.

    Explained in: node-saml README (github.com), checked 2026-10-14

    Done when: The genuine login still passes, the two attacks still fail, and you can say which element each signature covered in both configurations.

  • 10. Rotate the IdP's signing key: in Keycloak's realm keys add a new RSA key provider with a higher priority, log in again and watch the SP reject the response; then replace the SP's certificate with the new one from the descriptor and log in again. (Read, not run by the learning center.)

    Certificate rotation is the most common SAML outage; the Entra tutorial shows the IdP side and this step shows the SP side.

    Explained in: Microsoft Entra: Manage certificates for federated single sign-on (learn.microsoft.com), checked 2026-10-14

    Done when: The SP fails with a signature error until its idpCert is updated, then succeeds, and your runbook note has the rotation steps and where the expiry date is recorded.