Quickstart¶
This page walks through a complete Web Browser SSO exchange using the in-process helpers, so you can run it end to end without a network or a real IdP/SP.
Service Provider: process a response¶
Given the XML of a SAML Response received at your Assertion Consumer Service
(ACS) endpoint, verify its signature and extract the authenticated identity:
from pygamlastan import xml, crypto, security, profiles
# 1. Verify the enveloped XML-DSig signature using the trusted IdP cert.
verifier = crypto.SamlVerifier.from_cert(idp_certificate_pem)
verified = verifier.verify_enveloped(response_xml)
# 2. Parse the response into owned Python objects.
response = xml.parse_response(response_xml)
# 3. Validate and extract identity. `verified_signed_ids` ties the
# signed-assertion requirement to the cryptographic verification above.
result = profiles.process_response(
response,
security.SecurityConfig(), # production defaults
sp_entity_id="https://sp.example.org/sp",
acs_url="https://sp.example.org/acs",
expected_idp_entity_id="https://idp.example.org",
expected_request_id="_the_request_id", # None for unsolicited
verified_signed_ids=verified.signed_reference_ids(),
replay_cache=security.InMemoryReplayCache(),
)
print(result.name_id)
print(result.attributes_dict()) # {"mail": ["alice@example.org"], ...}
Identity Provider: build a response¶
On the IdP side, turn an authenticated principal into a SAML Response:
from pygamlastan import core, profiles
options = profiles.ResponseOptions(
idp_entity_id="https://idp.example.org",
sp_entity_id="https://sp.example.org/sp",
acs_url="https://sp.example.org/acs",
in_response_to="_the_request_id",
authn_context_class_ref=core.AUTHN_CONTEXT_PASSWORD,
attributes=[
core.Attribute("mail", values=["alice@example.org"]),
core.Attribute("displayName", values=["Alice"]),
],
)
name_id = core.NameId("alice@example.org", format=core.NAMEID_TRANSIENT)
response = profiles.create_response(options, name_id)
unsigned_xml = response.to_xml() # next: sign it (see the signing guide)
A full round trip¶
Putting both sides together, with permissive validation so the example does
not require real signatures:
from datetime import datetime, timezone
from pygamlastan import core, xml, profiles, security
now = datetime(2026, 6, 25, 10, 0, 0, tzinfo=timezone.utc)
IDP, SP, ACS = "https://idp.example.org", "https://sp.example.org/sp", "https://sp.example.org/acs"
# IdP issues a response for request "_req1".
options = profiles.ResponseOptions(
IDP, SP, ACS, in_response_to="_req1",
authn_context_class_ref=core.AUTHN_CONTEXT_PASSWORD,
attributes=[core.Attribute("mail", values=["alice@example.org"])],
)
response = profiles.create_response(options, core.NameId("alice", format=core.NAMEID_TRANSIENT), now=now)
# SP consumes it.
parsed = xml.parse_response(response.to_xml())
result = profiles.process_response(
parsed, security.SecurityConfig.permissive(), SP, ACS, IDP,
expected_request_id="_req1", now=now, replay_cache=security.InMemoryReplayCache(),
)
assert result.name_id == "alice"
Where to go next¶
Service Provider integration and Identity Provider integration cover each side in depth, including the AuthnRequest.
Signing, verification, and encryption explains file-key and PKCS#11/HSM signing and verification.
Validation and replay protection documents the security configuration, the structured validation result, and replay protection.