SSO & SCIM setup
Configure SAML 2.0 single sign-on and SCIM 2.0 user provisioning for Okta, Microsoft Entra ID (Azure AD), Google Workspace, and OneLogin.
Pact federates with any SAML 2.0 IdP and supports SCIM 2.0 for automatic user lifecycle management. SAML carries the login. SCIM carries provisioning, deprovisioning, and group membership.
This page is the operator setup guide for the four most common IdPs. Pact is IdP-agnostic — anything that speaks SAML 2.0 (HTTP-POST binding on the ACS, HTTP-Redirect on the AuthnRequest) will work, including AD FS, Ping, JumpCloud, and Authentik.
What you get
- Single sign-on — SAML 2.0 with assertion-signature verification, replay protection, audience restriction, and clock-skew tolerance per SAML Core §4.1.4.
- JIT user provisioning — first login from your IdP creates the Pact user record. No manual seat onboarding.
- SCIM 2.0 user lifecycle — push user creates, updates, deactivations, and group memberships from your IdP. Standard
/scim/v2/Usersand/scim/v2/Groupsendpoints. - Per-domain SSO routing — users entering their work email at
/loginare auto-redirected to the right IdP via a discovery probe. - SP-initiated and IdP-initiated logins — both bindings work; the ACS handler validates
InResponseTocorrectly in both cases. - Single Logout — SP- and IdP-initiated SLO with embedded XML-DSig signature verification (closes the XML signature wrapping attack).
- Full audit log — every SAML and SCIM event lands in the tenant audit log under the
auth.saml.*andauth.scim.*action namespaces.
Where to set it up
Configure SSO in the admin UI — never through environment variables or platform secrets.
- Wizard —
/admin/ssowalks through provider cards for Google Workspace, Microsoft Entra ID, and Okta. Domain claims, the SSO-required toggle, and the auto-join-by-domain switch all live here. - Direct SAML CRUD —
/admin/sso-samllists every IdP the tenant has registered, lets you paste IdP metadata XML or fill in entityID / SSO URL / certificate by hand, and offers a "Test connection" button that opens an SP-initiated login in a new tab. - SCIM token + groups —
/admin/scim-groupsgenerates the SCIM bearer token your IdP pushes into theAuthorization: Bearer …header and shows the inbound provisioning audit feed.
Quick provider setup
Okta (SAML)
- In Pact, open
/admin/sso-saml→ Add IdP → copy the SP metadata URL shown in the dialog. - In Okta admin → Applications → Create App Integration → SAML 2.0.
- App name: "Pact". Logo: download from the Pact brand kit (or skip).
- Single sign on URL: paste the ACS URL from Pact — it ends in your workspace ID (
…/v1/sso/saml/acs/<workspace-id>). - Audience URI (SP Entity ID): paste the SP entity ID from Pact (
…/v1/sso/saml, not the metadata URL). - Name ID format:
EmailAddress. Application username:Email. - Attribute statements — add these four:
email→user.emailfirstName→user.firstNamelastName→user.lastNamegroups(Group Attribute Statement, filter "Matches regex:.*") →user.groups
- In Okta → Sign-On tab → View SAML Setup Instructions → copy the Identity Provider metadata URL.
- Back in Pact → paste it into the IdP metadata URL field, save, then click Test connection.
Microsoft Entra ID / Azure AD (SAML)
- In Pact, open
/admin/sso-samland copy the SP metadata URL. - In the Entra portal → Enterprise applications → New application → Create your own application → Integrate any other application you don't find in the gallery.
- Select Single sign-on → SAML.
- Basic SAML Configuration — paste the SP Identifier (entity ID), Reply URL (ACS), and Sign on URL from Pact.
- Attributes & Claims:
email→user.mailfirstName→user.givennamelastName→user.surnamegroups→ group claim with "All groups" or "Groups assigned to the application"
- Download the Federation Metadata XML and paste it into Pact's IdP metadata field, save, then Test connection.
- Assign the app to the users / groups that should be able to sign in.
Google Workspace (OIDC via wizard)
Google Workspace uses OIDC in the Pact wizard — no XML required.
- In Pact, open
/admin/sso→ Google Workspace card → Set up. - In Google Cloud Console → APIs & Services → Credentials → OAuth client ID → Web application.
- Authorized redirect URI: paste the redirect URI shown in Pact (
https://app.pact.place/v1/sso/oauth/callback). - Copy the Client ID and Client secret into the Pact wizard.
- Add the email domains you want to auto-route (e.g.
@yourcompany.com). - Click Save then Test connection.
OneLogin (SAML)
- In Pact, open
/admin/sso-samland copy the SP metadata URL + ACS URL. - OneLogin admin → Applications → Add App → search for SAML Custom Connector (Advanced).
- Configuration tab:
- Audience (EntityID) → paste Pact SP entityID.
- Recipient → paste Pact ACS URL.
- ACS (Consumer) URL Validator →
^https:\/\/app\.pact\.place\/v1\/sso\/saml\/acs$. - ACS (Consumer) URL → paste Pact ACS URL.
- SAML signature element → Assertion.
- SAML nameID format → Email.
- Parameters tab — map
email,firstName,lastName,groupsto the matching OneLogin user attributes. - SSO tab → copy the Issuer URL and X.509 Certificate.
- In Pact → fill IdP Entity ID, SSO URL, X.509 cert by hand, save, then Test connection.
SCIM provisioning
SCIM is independent of SAML — you can run SAML without SCIM, or both. SCIM means your IdP can push new hires, role changes, and offboardings into Pact without an admin doing it by hand.
- In Pact →
/admin/scim-groups→ Generate SCIM token. Copy it once — Pact never shows it again. - In your IdP's app → Provisioning → Configure API integration (or equivalent).
- SCIM Connector base URL:
https://app.pact.place/scim/v2 - Authorization:
Bearer <token>— bearer token mode. - Map the standard SCIM attributes (
userName,name.givenName,name.familyName,emails[0].value,active). Pact reads them from the standard SCIM 2.0 user schema (RFC 7643). - Map groups → Pact roles via the group sync section in
/admin/scim-groups. Each Pact role can be claimed by one or more IdP group names.
The supported SCIM operations:
| Operation | Endpoint | What it does in Pact |
|---|---|---|
| Create user | POST /scim/v2/Users | Creates the local user, JIT-provisions tenant membership. |
| Update user | PATCH /scim/v2/Users/:id | Updates name/email; active=false deactivates. |
| Soft-delete | PATCH active=false | User can no longer log in. Data is retained. |
| Hard-delete | DELETE /scim/v2/Users/:id | Removes the user row. SOC 2 reviewers typically prefer soft-delete. |
| Create group | POST /scim/v2/Groups | Creates a SCIM group; map to a Pact role for RBAC. |
| Update group membership | PATCH /scim/v2/Groups/:id | Adds / removes members; role mapping fires on the next member login. |
| List + filter | GET /scim/v2/Users?filter=... | Standard SCIM filter syntax (RFC 7644). |
Force-SSO and per-domain auto-join
Once Test connection succeeds, flip Require SSO for all users in /admin/sso. After that:
- Email/password login is blocked for any account in your tenant.
- The login page detects a verified SAML domain on email blur and renders Sign in with SSO above the password field.
- The auto-join by verified domain switch is saved but not yet applied at sign-in. New users from your IdP are provisioned just-in-time on their first SAML login either way.
Domain claims require DNS TXT verification. Publish the TXT record value Pact gives you, then click Check TXT record — Pact checks when you click; it does not poll. Until the domain is verified, typing an address at that domain on the login page does not route to your SSO, even if a SAML connection names the domain: the admin page says "Unverified — sign-in routing is off until the TXT record is found". Ownership is exclusive — one Pact workspace per domain. If another workspace has already verified it, the check says so ("Owned elsewhere"); contact Pact support to transfer it.
Your Okta or Entra app tile (IdP-initiated sign-in) and direct SSO links work without a verified domain.
What gets audited
Every SAML and SCIM event lands in the tenant audit log under auth.saml.* and auth.scim.*. Examples:
auth.saml.login.start— SP-initiated login was kicked off.auth.saml.acs.success— assertion validated, session issued.auth.saml.acs.failure— assertion rejected; thereasonfield carries the taxonomy (signature_invalid,replay,audience_mismatch,notbefore,notafter,subject_missing, ...).auth.saml.slo.success/.failure— Single Logout.auth.saml.idp.created/.updated/.deleted— admin actions on the IdP config row.auth.scim.user.created/.updated/.deactivated/.deleted.auth.scim.group.created/.updated/.membership_changed.
Filter the audit log by action prefix in /admin/security/audit-log.
Troubleshooting
"Test connection" opens a tab but the IdP rejects the AuthnRequest. Your SP metadata in the IdP is stale. Re-download Pact's SP metadata XML and re-paste it. The entityID changes if you change your custom domain.
Login fails with signature_invalid in the audit log. The IdP signing cert in Pact doesn't match what the IdP is using. Re-fetch the IdP metadata URL or paste the current X.509 cert.
Login fails with audience_mismatch. The IdP is sending the wrong <Audience> element. It must equal Pact's SP entityID exactly.
SCIM returns 401 on every request. The bearer token rolled or was revoked. Re-generate in /admin/scim-groups and update your IdP.
Users land in Pact but with no role. No SCIM group → Pact role mapping fired. Add a mapping in /admin/scim-groups or grant a default role in /admin/iam.
My IdP isn't listed in the wizard. Use the Add IdP dialog in /admin/sso-saml — the manual fields work for any SAML 2.0 IdP. The wizard is a convenience layer; everything is generic SAML underneath.