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.

Bash
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.

Bash
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.

Bash
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.

Bash
# 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.

Bash
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)

Bash
curl https://tetrapus.example.com/api/v1/admin/saml/providers \
  -H "Authorization: Bearer $ADMIN_TOKEN"

Create provider

Bash
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

Bash
# 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

MethodPathAuthPurpose
GET/api/v1/saml/providersnoneList enabled IdPs (login page)
GET/api/v1/saml/{id}/metadatanoneSP metadata XML for IdP
GET/api/v1/saml/{id}/sso-startnoneBegin SP-initiated SSO
POST/api/v1/saml/{id}/acsnoneReceive SAMLResponse
POST/api/v1/saml/{id}/slononeSingle Logout
GET/api/v1/admin/saml/providersOrgAdminList all (incl. disabled)
POST/api/v1/admin/saml/providersOrgAdminCreate
GET/api/v1/admin/saml/providers/{id}OrgAdminRead one
PATCH/api/v1/admin/saml/providers/{id}OrgAdminPartial update
DELETE/api/v1/admin/saml/providers/{id}OrgAdminSoft-delete

GUI admin tab walkthrough

The same CRUD is exposed in-app for anyone who'd rather not reach for curl:

  1. Workspace (top-right) → Profile menu.
  2. Org admin link (visible only to OrgAdmins).
  3. SAML tab. The table lists every provider with name, entity ID, enabled status, and last-used timestamp.
  4. 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)
  5. Click Save. The form validates the cert PEM and the SSO URL is HTTPS before POSTing.
  6. Test button on each row launches /sso-start in a new tab.

Related

Questions?

Reach out for help with integration, deployment, or custom domain codecs.