SSO Configuration Guide
This guide covers SSO configuration for org admins. It describes how to connect Microsoft Entra ID via OIDC (OAuth 2.0), configure a SAML 2.0 identity provider, rotate SCIM bearer tokens, and select the authentication method appropriate for your deployment.
Auth methods
Section titled “Auth methods”Arbitex supports three authentication methods:
| Method | Protocol | Use case |
|---|---|---|
| Entra ID OIDC | OAuth 2.0 / OpenID Connect | Entra ID (Azure AD) tenants — recommended for most organizations |
| SAML 2.0 | SAML 2.0 | Any SAML-compatible IdP (Okta, PingFederate, AD FS, Entra ID in SAML mode) |
| Username + password | Arbitex native | Local accounts not tied to an external IdP |
OIDC and SAML can be active simultaneously. Users authenticate via whichever method their client initiates. Native accounts continue to work alongside SSO.
Part 1: Entra ID OIDC (OAuth 2.0)
Section titled “Part 1: Entra ID OIDC (OAuth 2.0)”How OIDC SSO works
Section titled “How OIDC SSO works”1. Client requests: GET /api/auth/oauth/google/authorize2. Arbitex returns { authorization_url }3. Client redirects user to authorization_url (Microsoft login page)4. User authenticates with Entra ID; Microsoft redirects to callback URI with code5. Client sends: POST /api/auth/oauth/google/callback { code, state }6. Arbitex exchanges code for tokens, validates OIDC ID token7. Arbitex provisions user account if first login (JIT provisioning)8. Arbitex returns { access_token, refresh_token, user }The email_verified claim in the ID token must be true. Authentication is rejected if the claim is absent or false.
JIT-provisioned users receive the USER role by default. Admin role must be assigned separately after first login.
Prerequisites
Section titled “Prerequisites”- Microsoft Azure subscription with Entra ID
- Permission to create App Registrations in Entra ID
- Arbitex platform environment variables accessible to platform operators
Step 1: Register an application in Entra ID
Section titled “Step 1: Register an application in Entra ID”- Sign in to the Azure Portal.
- Navigate to Microsoft Entra ID → App registrations → New registration.
- Configure:
- Name:
Arbitex Gateway(or your preferred display name) - Supported account types:
Accounts in this organizational directory only(single tenant) for most deployments - Redirect URI: Leave blank — configure in Step 2
- Name:
- Click Register.
- Note the Application (client) ID and Directory (tenant) ID from the Overview page.
Step 2: Configure redirect URIs
Section titled “Step 2: Configure redirect URIs”- Navigate to Authentication → Add a platform → Web.
- Add the redirect URI:
https://api.arbitex.ai/api/auth/oauth/google/callback
- Leave Implicit grant and hybrid flows checkboxes unchecked — Arbitex uses the authorization code flow.
- Click Save.
Step 3: Create a client secret
Section titled “Step 3: Create a client secret”- Navigate to Certificates & secrets → New client secret.
- Set a description and expiry period.
- Click Add.
- Copy the secret Value immediately — it is not shown again after you navigate away.
Step 4: Configure API permissions
Section titled “Step 4: Configure API permissions”Arbitex requires these Microsoft Graph delegated permissions:
| Permission | Purpose |
|---|---|
openid | OIDC login |
profile | Display name for JIT provisioning |
email | Email address (primary user identifier) |
- Navigate to API permissions → Add a permission → Microsoft Graph → Delegated permissions.
- Add
openid,profile, andemail. - Click Grant admin consent for [your tenant] if your tenant requires admin consent for delegated permissions.
Step 5: Configure Arbitex platform
Section titled “Step 5: Configure Arbitex platform”Set these environment variables on the Arbitex Platform API:
| Variable | Value |
|---|---|
GOOGLE_CLIENT_ID | Application (client) ID from Step 1 |
GOOGLE_CLIENT_SECRET | Client secret value from Step 3 |
GOOGLE_REDIRECT_URI | https://api.arbitex.ai/api/auth/oauth/google/callback |
In production deployments, store these values in Azure Key Vault and inject via the Key Vault CSI driver at pod startup. Do not store them in plaintext configuration files.
Restart the Platform API after setting these variables.
Step 6: Verify OIDC is enabled
Section titled “Step 6: Verify OIDC is enabled”GET https://api.arbitex.ai/api/auth/oauth/statusResponse when configured:
{ "sso_enabled": true }If sso_enabled is false, the environment variables are not being read correctly. Verify that Key Vault secrets are accessible and the pod has restarted.
Part 2: SAML 2.0 IdP configuration
Section titled “Part 2: SAML 2.0 IdP configuration”SAML IdP configuration is managed via the admin API at /api/admin/saml/idp. Arbitex acts as the Service Provider (SP).
Service Provider metadata
Section titled “Service Provider metadata”| Parameter | Value |
|---|---|
| ACS URL | https://api.arbitex.ai/api/auth/saml/acs |
| Entity ID (SP) | https://api.arbitex.ai |
| NameID format | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress |
| Binding | HTTP POST |
Use these values when configuring Arbitex as a relying party in your IdP (Entra ID enterprise app, Okta app, AD FS relying party trust, or PingFederate SP connection).
IdP configuration fields
Section titled “IdP configuration fields”| Field | Required | Description |
|---|---|---|
name | Yes | Display name for this IdP configuration |
entity_id | Yes | IdP Entity ID from IdP metadata (must be unique) |
sso_url | Yes | IdP SSO endpoint URL (HTTP POST binding) |
slo_url | No | IdP Single Logout endpoint URL |
x509_cert | Yes | IdP signing certificate (PEM format, without headers) |
attribute_mapping | No | JSON object mapping SAML attributes to Arbitex fields |
is_active | Yes | true to enable this IdP for login |
Step 1: Create a SAML IdP configuration
Section titled “Step 1: Create a SAML IdP configuration”POST /api/admin/saml/idpAuthorization: Bearer <admin_token>Content-Type: application/json
{ "name": "Entra ID SAML", "entity_id": "https://sts.windows.net/{tenant_id}/", "sso_url": "https://login.microsoftonline.com/{tenant_id}/saml2", "slo_url": "https://login.microsoftonline.com/{tenant_id}/saml2", "x509_cert": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA...", "attribute_mapping": { "email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", "display_name": "http://schemas.microsoft.com/identity/claims/displayname" }, "is_active": true}Response (201 Created):
{ "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "name": "Entra ID SAML", "entity_id": "https://sts.windows.net/{tenant_id}/", "sso_url": "https://login.microsoftonline.com/{tenant_id}/saml2", "slo_url": "https://login.microsoftonline.com/{tenant_id}/saml2", "x509_cert": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA...", "attribute_mapping": { ... }, "is_active": true, "created_at": "2026-03-11T00:00:00Z", "updated_at": "2026-03-11T00:00:00Z"}The entity_id must be unique. If a configuration with the same entity_id already exists, the request returns 409 Conflict.
Step 2: Configure Entra ID as SAML IdP (optional — Entra ID-specific)
Section titled “Step 2: Configure Entra ID as SAML IdP (optional — Entra ID-specific)”If you are configuring Entra ID in SAML mode rather than OIDC mode:
- In the Azure Portal, navigate to Microsoft Entra ID → Enterprise applications → New application → Create your own application.
- Select Integrate any other application you don’t find in the gallery.
- Under Single sign-on → SAML, configure:
- Entity ID / Identifier:
https://api.arbitex.ai - Reply URL (ACS URL):
https://api.arbitex.ai/api/auth/saml/acs - Sign on URL: Leave blank for IdP-initiated flow, or set to your portal URL
- Entity ID / Identifier:
- Download the Certificate (Base64) from the SAML Signing Certificate section.
- Note the Login URL and Azure AD Identifier (Entity ID) from the Setup section.
- Use those values in the
sso_urlandentity_idfields when callingPOST /api/admin/saml/idp.
Step 3: List IdP configurations
Section titled “Step 3: List IdP configurations”GET /api/admin/saml/idpAuthorization: Bearer <admin_token>Response:
{ "items": [ { "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "name": "Entra ID SAML", "entity_id": "https://sts.windows.net/{tenant_id}/", "is_active": true, ... } ], "total": 1}Step 4: Update an IdP configuration
Section titled “Step 4: Update an IdP configuration”PUT /api/admin/saml/idp/{idp_id}Authorization: Bearer <admin_token>Content-Type: application/json
{ "x509_cert": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A...", "is_active": true}Only fields included in the request body are updated. To rotate a signing certificate, update only x509_cert. The entity_id uniqueness constraint is re-validated if entity_id is included.
Step 5: Delete an IdP configuration
Section titled “Step 5: Delete an IdP configuration”DELETE /api/admin/saml/idp/{idp_id}Authorization: Bearer <admin_token>Returns 204 No Content. After deletion, users cannot authenticate via this IdP.
Part 3: SCIM token rotation
Section titled “Part 3: SCIM token rotation”Arbitex supports SCIM 2.0 for automated user and group provisioning from Entra ID, Okta, and other SCIM-compatible IdPs. SCIM authentication uses a per-org bearer token separate from JWT access tokens.
How SCIM tokens work
Section titled “How SCIM tokens work”- Each org has one active SCIM token at a time, stored as a bcrypt hash.
- The raw token value is returned once at generation time and cannot be retrieved afterwards.
- Rotating a token invalidates the previous token immediately.
- SCIM provisioning requests must present the current token in the
Authorization: Bearerheader.
Rotate the SCIM token
Section titled “Rotate the SCIM token”POST /v1/orgs/{org_id}/scim/token/rotateAuthorization: Bearer <admin_token>Replace {org_id} with the UUID of your organization.
Response (200 OK):
{ "token": "abc123xyz...", "org_id": "550e8400-e29b-41d4-a716-446655440000", "created_at": "2026-03-11T00:00:00Z"}Store the token value immediately. This is the only time the raw value is returned. The platform stores only the bcrypt hash.
After rotation:
- Copy the new token value.
- Update the SCIM provisioning configuration in your IdP (Entra ID or Okta) with the new token.
- Verify provisioning by triggering a test sync in your IdP.
The previous token is invalidated at the time of rotation. Any provisioning requests using the old token return 401 Unauthorized immediately.
SCIM endpoint reference
Section titled “SCIM endpoint reference”| Endpoint | Method | Description |
|---|---|---|
/scim/v2/Users | GET | List users |
/scim/v2/Users/{user_id} | GET | Get a single user |
/scim/v2/Users | POST | Create a user |
/scim/v2/Users/{user_id} | PUT | Replace user attributes |
/scim/v2/Users/{user_id} | PATCH | Partial user update |
/scim/v2/Users/{user_id} | DELETE | Deactivate a user (soft delete) |
/scim/v2/Groups | GET | List groups |
/scim/v2/Groups/{group_id} | GET | Get a single group |
/scim/v2/Groups | POST | Create a group |
/scim/v2/Groups/{group_id} | PUT | Replace group attributes |
/scim/v2/Groups/{group_id} | PATCH | Partial group update |
/scim/v2/Groups/{group_id} | DELETE | Delete a group |
SCIM DELETE for users performs a soft delete (is_active=false) rather than removing the user record, preserving audit history.
Arbitex Group extension schema
Section titled “Arbitex Group extension schema”Arbitex extends the SCIM Group resource with additional attributes for policy configuration. The extension URN is urn:ietf:params:scim:schemas:extension:arbitex:2.0:Group. Your IdP can discover the schema via GET /scim/v2/Schemas.
Available extension attributes:
| Attribute | Type | Description |
|---|---|---|
dlpPolicy | string | DLP policy ID to apply to the group |
modelAccess | string | Model access configuration |
complianceBundles | list | Compliance bundle IDs to assign |
quotas | object | Per-group usage quotas |
Part 4: Auth method selection
Section titled “Part 4: Auth method selection”Coexistence
Section titled “Coexistence”OIDC, SAML, and native authentication can operate simultaneously. There is no exclusivity constraint. Users are matched to their auth method based on how they initiate the login:
- OIDC: client calls
/api/auth/oauth/google/authorize→ user redirected to Microsoft - SAML: IdP-initiated or SP-initiated via the SAML endpoint
- Native: client posts
{ email, password }to/api/auth/login
Disabling OIDC
Section titled “Disabling OIDC”Remove the GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and GOOGLE_REDIRECT_URI environment variables and restart the Platform API. The /api/auth/oauth/status endpoint returns { "sso_enabled": false }.
Users provisioned via OIDC SSO retain their accounts. They must use native password authentication or SAML after OIDC is disabled.
Disabling a SAML IdP
Section titled “Disabling a SAML IdP”Set is_active: false on the IdP configuration:
PUT /api/admin/saml/idp/{idp_id}Authorization: Bearer <admin_token>Content-Type: application/json
{ "is_active": false }Or delete the configuration entirely (DELETE /api/admin/saml/idp/{idp_id}). Deletion is permanent.
Enforcing SSO-only authentication
Section titled “Enforcing SSO-only authentication”Native authentication (username + password) is not disabled by enabling SSO. Contact your Arbitex platform operator to disable native login at the deployment level if you require SSO-only enforcement.
See also
Section titled “See also”- Entra ID SCIM provisioning — SCIM user and group sync setup for Entra ID
- SAML SSO guide — Legacy SAML guide (superseded by this guide for new deployments)
- User & group management — Manual invite flow, group creation, and member management
- MFA configuration — TOTP-based multi-factor authentication
- Groups & RBAC — Group-based access control and model access