SAML Admin & API
Complete REST surface for managing SAML IdPs, plus the GUI admin tab walkthrough. All admin routes require
the OrgAdmin role on the targeted Org.
Public endpoints (discovery, metadata, ACS, SLO) are unauthenticated by design.
Public discovery endpoints
Used by the login page and the IdP itself. No bearer token needed.
List enabled providers
Login page calls this to render the "Sign in with…" buttons. Returns only enabled providers, no secret material.
curl https://tetrapus.example.com/api/v1/saml/providers
# Response
[
{
"id": "01HVXY3K8B0RJ7P0ZQK4S6F4N1",
"name": "Acme Okta",
"org_id": "01HV…"
}
] SP metadata XML
Hand this URL to the IdP admin — they can ingest it directly to auto-populate ACS URL, entity ID, and the (optional) SP signing certificate.
curl https://tetrapus.example.com/api/v1/saml/01HVXY3K8B.../metadata
# Response: application/samlmetadata+xml
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://tetrapus.example.com/saml/01HVXY...">
<SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://tetrapus.example.com/api/v1/saml/01HVXY.../acs" index="0"/>
</SPSSODescriptor>
</EntityDescriptor> Start SP-initiated SSO
User-facing redirect endpoint. Issues 302 to the IdP with a SAMLRequest in the query string.
curl -i https://tetrapus.example.com/api/v1/saml/01HVXY.../sso-start?relay=/dashboard
# HTTP/1.1 302 Found
# Location: https://acme.okta.com/app/...?SAMLRequest=fZJBb...&RelayState=%2Fdashboard ACS — receive SAMLResponse
The IdP POSTs here with the signed assertion. On success, sets the Tetrapus session cookie and 302s to RelayState.
# IdP-initiated; you generally do not call this directly.
curl -X POST https://tetrapus.example.com/api/v1/saml/01HVXY.../acs \
-F "SAMLResponse=PHNhbWxwOlJlc3BvbnNl..." \
-F "RelayState=/dashboard" SLO — single logout
IdP-initiated logout. Tetrapus revokes the session and (best-effort) responds with a LogoutResponse.
curl -X POST https://tetrapus.example.com/api/v1/saml/01HVXY.../slo \
-F "SAMLRequest=PHNhbWxwOkxvZ291dFJlcXVlc3Q..." Admin CRUD endpoints
All require an OrgAdmin bearer token. Mounted under /api/v1/admin/saml/providers.
List providers (admin)
curl https://tetrapus.example.com/api/v1/admin/saml/providers \
-H "Authorization: Bearer $ADMIN_TOKEN" Create provider
curl -X POST https://tetrapus.example.com/api/v1/admin/saml/providers \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Okta",
"entity_id": "http://www.okta.com/exk1abcXYZ",
"sso_url": "https://acme.okta.com/app/acme_tetrapus_1/exk1abc/sso/saml",
"slo_url": "https://acme.okta.com/app/acme_tetrapus_1/exk1abc/slo/saml",
"x509_cert_pem": "-----BEGIN CERTIFICATE-----\nMIID...==\n-----END CERTIFICATE-----",
"name_id_format": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
"attr_mapping": {
"email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
"given_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
"family_name":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
"name_id_as_subject": true
},
"enabled": true
}' Get / Update / Delete by id
# Read
curl https://tetrapus.example.com/api/v1/admin/saml/providers/01HVXY... \
-H "Authorization: Bearer $ADMIN_TOKEN"
# Patch (any field nullable; only present keys are applied)
curl -X PATCH https://tetrapus.example.com/api/v1/admin/saml/providers/01HVXY... \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "enabled": false }'
# Delete (soft-deletes; existing sessions remain valid until expiry)
curl -X DELETE https://tetrapus.example.com/api/v1/admin/saml/providers/01HVXY... \
-H "Authorization: Bearer $ADMIN_TOKEN" Route summary
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /api/v1/saml/providers | none | List enabled IdPs (login page) |
| GET | /api/v1/saml/{id}/metadata | none | SP metadata XML for IdP |
| GET | /api/v1/saml/{id}/sso-start | none | Begin SP-initiated SSO |
| POST | /api/v1/saml/{id}/acs | none | Receive SAMLResponse |
| POST | /api/v1/saml/{id}/slo | none | Single Logout |
| GET | /api/v1/admin/saml/providers | OrgAdmin | List all (incl. disabled) |
| POST | /api/v1/admin/saml/providers | OrgAdmin | Create |
| GET | /api/v1/admin/saml/providers/{id} | OrgAdmin | Read one |
| PATCH | /api/v1/admin/saml/providers/{id} | OrgAdmin | Partial update |
| DELETE | /api/v1/admin/saml/providers/{id} | OrgAdmin | Soft-delete |
GUI admin tab walkthrough
The same CRUD is exposed in-app for anyone who'd rather not reach for
curl:
- Workspace (top-right) → Profile menu.
- Org admin link (visible only to OrgAdmins).
- SAML tab. The table lists every provider with name, entity ID, enabled status, and last-used timestamp.
- Click Add IdP. The form mirrors the JSON body from the create endpoint:
- Name (display label for the login button)
- Entity ID
- SSO URL
- SLO URL (optional)
- Signing certificate (paste PEM, or upload .crt)
- NameID format (dropdown — emailAddress, persistent, transient, unspecified)
- Attribute mapping (key/value editor)
- Enabled (toggle)
- Click Save. The form validates the cert PEM and the SSO URL is HTTPS before POSTing.
- Test button on each row launches
/sso-startin a new tab.
Related
- SAML overview & flow diagram
- SCIM 2.0 — pair with SAML for full SSO + provisioning
- ← Federation overview
Questions?
Reach out for help with integration, deployment, or custom domain codecs.