diff --git a/docs/source/guide/auth_setup.md b/docs/source/guide/auth_setup.md index 77818fdd0131..8fae8e9c6ef2 100644 --- a/docs/source/guide/auth_setup.md +++ b/docs/source/guide/auth_setup.md @@ -52,9 +52,12 @@ The details will vary depending on your IdP, but in general you will complete th 3. In the **Organization** field, ensure the domain matches the domain used for your organization in your IdP. 4. Copy the following URLs: - * **Assertion Consumer Service (ACS) URL with Audience (EntityID), and Recipient (Reply) details**---The IdP uses this URL to redirect users to after a successful authentication. - * **Login URL**---This is the URL that users will use to log in to Label Studio. - * **Logout URL**---This is the URL used to redirect users after successfully logging out of Label Studio. + * **Assertion Consumer Service (ACS) URL with Audience (EntityID), and Recipient (Reply) details**---The IdP uses this URL to redirect users to after a successful authentication. Format: `https:///saml//acs` + * **Login URL**---This is the URL that users will use to log in to Label Studio. Format: `https:///saml//login` + * **Logout URL**---This is the URL used to redirect users after successfully logging out of Label Studio. Format: `https:///saml//logout` + +!!! note + Label Studio does not implement SAML Single Logout (SLO) to the IdP. The logout URL only ends the local Label Studio session. #### From your IdP: @@ -96,13 +99,15 @@ If your Entra ID is configured with default claim URIs, use: | LastName | `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname` | | Groups | `http://schemas.microsoft.com/ws/2008/06/identity/claims/groups` | - +!!! warning "Important: Group names vs. Object IDs in Entra ID" + If you use group-based mappings (roles, workspaces, projects), you must configure Entra ID to send **group names** (not Object IDs) in the groups claim. In **User Attributes & Claims → Groups returned in claim**, select **Groups assigned to the application** and set **Source attribute** to `sAMAccountName` or another human-readable group property. Sending Object IDs instead of names will prevent group mappings from working correctly. #### From Label Studio: 1. Return to the SSO & SAML page. 2. Upload the metadata XML file or specify the metadata URL. -3. Set up group mappings. These can also be added or edited later. +3. Select the appropriate IdP provider preset (e.g. `azure` for Entra ID) to auto-fill attribute mapping names, or configure them manually to match what your IdP sends. +4. Set up group mappings. These can also be added or edited later. Ensure the group name you enter is the same as the group name sent as an attribute in a SAML authentication response by your IdP. @@ -117,15 +122,140 @@ If your Entra ID is configured with default claim URIs, use: You can map a group to different roles across multiple projects. You can also map multiple groups to the same roles and the same projects. For more information on roles, see [Roles in Label Studio Enterprise](manage_users#Roles-in-Label-Studio-Enterprise). If you select **Inherit**, the group will inherit the role set above under **Organization Roles to Groups Mapping.** If the group is inheriting the Not Activated role, the users are mapped to the project, but they are not actually assigned to the project until the group is synced (meaning that the user authenticates with SSO). -4. Click **Save**. +5. Click **Save**. + +6. Test the configuration by logging in to Label Studio Enterprise with your SSO account. -5. Test the configuration by logging in to Label Studio Enterprise with your SSO account. +#### Group mapping behavior +| Mapping Type | Behavior | +| --- | --- | +| Organization Roles (`roles_groups`) | If a user belongs to multiple role groups, the most elevated role wins. Available roles: Administrator, Manager, Reviewer, Annotator. The Owner role cannot be assigned via SAML or SCIM. | +| Workspaces (`workspaces_groups`) | A user can be mapped to multiple workspaces through multiple group memberships. Workspaces are automatically created if they do not exist when a mapping is triggered. | +| Projects (`projects_groups`) | Format: `{"project_id": , "group": "", "role": ""}`. Available project roles: Annotator, Reviewer, or Inherit. The most elevated role wins when a user is in multiple groups mapped to the same project. | + +!!! note + Group name matching is **case-sensitive** for all mapping types. `LS-Admins` and `ls-admins` are treated as different groups. Ensure exact casing matches between your IdP group names and Label Studio mapping configurations. + +### SAML SSO Settings API + +You can also configure SAML settings programmatically using the API: + +| Method | Endpoint | Description | +| --- | --- | --- | +| `GET` | `/api/saml/settings` | Retrieve current SAML settings (includes computed SP URLs) | +| `POST` | `/api/saml/settings` | Update SAML settings (partial update supported) | +| `DELETE` | `/api/saml/settings` | Reset SAML configuration | +| `POST` | `/api/saml/settings/validate-metadata-url` | Validate a metadata URL is reachable and contains valid XML | + +!!! warning + Using `DELETE /api/saml/settings` clears all SCIM group assignments (`WorkspaceGroupAssignment`, `OrganizationGroupAssignment`, and `ProjectGroupAssignment` records) and resets `ScimGroupSettings` for the organization. If you need to reconfigure SAML, re-save your SCIM settings afterward and wait for the next group sync to rebuild assignments. + +**Example: Configure SAML via the API** + +```bash +curl -X POST "https:///api/saml/settings" \ + -H "Authorization: Token " \ + -H "Content-Type: application/json" \ + -d '{ + "domain": "contoso.com", + "metadata_url": "https://login.microsoftonline.com//federationmetadata/2007-06/federationmetadata.xml?appid=", + "idp_provider": "azure", + "mapping_email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", + "mapping_first_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname", + "mapping_last_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname", + "mapping_groups": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groups", + "roles_groups": [ + ["Administrator", "LS-Admins"], + ["Annotator", "LS-Annotators"] + ], + "workspaces_groups": [ + ["Engineering", "LS-Engineering-Team"] + ], + "projects_groups": [ + {"project_id": 42, "group": "LS-Project42-Reviewers", "role": "Reviewer"} + ] + }' +``` ### Setup SAML SSO with Okta video tutorial +### Set up SAML SSO with Microsoft Entra ID + +To set up SAML SSO specifically with Microsoft Entra ID (formerly Azure AD): + +#### Step 1: Create the Enterprise Application in Entra ID + +1. In the Azure Portal, go to **Entra ID → Enterprise Applications → New Application**. +2. Select **Create your own application** → **Integrate any other application not found in the gallery**. +3. Name it (e.g. `Label Studio SSO`) and create it. + +#### Step 2: Configure SAML in Entra ID + +1. Go to **Single sign-on → SAML**. +2. Under **Basic SAML Configuration**: + - **Identifier (Entity ID)**: Paste the ACS URL from Label Studio. + - **Reply URL (ACS URL)**: Paste the same ACS URL. + - **Sign on URL**: Paste the Login URL from Label Studio. +3. Under **User Attributes & Claims**, configure the attribute mappings using the Entra ID presets [shown above](#from-your-idp). +4. Under **SAML Signing Certificate**, download the **Federation Metadata XML** file (or copy the **App Federation Metadata URL**). + +#### Step 3: Configure SAML in Label Studio + +1. Go to **Organization → SSO & SAML**. +2. In the **Domain** field, enter the email domain(s) for your organization (comma-separated, e.g. `contoso.com`). This is used for domain-based SSO routing when users enter their email on the login page. +3. Upload the **Federation Metadata XML** file downloaded from Entra ID, or paste the **App Federation Metadata URL** in the metadata URL field. +4. Select `azure` as the IdP provider preset to auto-fill attribute mapping names, or configure them manually. +5. Configure group mappings as needed. +6. Click **Save**. + +#### Step 4: Assign users and test + +1. In Entra ID, go to **Enterprise Application → Users and groups → Add user/group**. +2. Assign users or groups to the application. +3. Test by navigating to the Label Studio Login URL, or by going to `https:///saml/sso-domain` and entering your email---Label Studio will look up the SAML config by domain and redirect to Entra ID. +4. After authenticating with Entra ID, you should be redirected back to Label Studio and logged in. + + +## JIT (Just-In-Time) provisioning + +When a user authenticates via SAML for the first time and no account exists, Label Studio automatically creates the account: + +- The user is created with the email from the SAML assertion. +- First name and last name are set from the assertion attributes (if mapped). +- The user is added to the organization with the **organization's default role**. +- Group mappings are then applied: org role, workspaces, and projects are assigned based on the SAML groups attribute. + +On subsequent SAML logins, the user's name is updated from the assertion, and group mappings are re-evaluated (roles, workspaces, projects are synced to match current group membership). + +### NameID format + +Label Studio uses `urn:oasis:names:tc:SAML:2.0:nameid-format:transient` as the default NameID format. The user's identity is resolved from the configured email attribute in the assertion, not from the NameID value. + +## SAML user lifecycle + +| Event | What happens in Label Studio | +| --- | --- | +| **First SAML login (new user)** | Account created (JIT), added to org with default role, then group mappings applied immediately. | +| **First SAML login (existing user, different org)** | User added to this org with default role, group mappings applied. | +| **Subsequent SAML login** | Name updated from assertion. Group mappings re-evaluated: roles, workspaces, and projects synced to match current groups (subject to manual management flags). | +| **User removed from all role groups** | If `manual_role_management` is off: role set to Deactivated on next login. If on: role unchanged. | +| **User removed from Entra ID app assignment** | No automatic change in Label Studio---user simply cannot authenticate via SSO anymore. Pair with SCIM deactivation for full lifecycle management. | + + +## SAML and SCIM interaction + +If your organization uses both SAML SSO and SCIM provisioning, be aware of the following interactions: + +- **Group mappings are configured separately.** SAML settings (`/api/saml/settings`) and SCIM settings (`/api/scim/settings`) each have their own `roles_groups`, `workspaces_groups`, and `projects_groups`. You can configure identical mappings in both, or use different mappings for each protocol. +- **SCIM project mappings take precedence over SAML.** When SCIM-driven project group assignments exist for a user, SAML skips its project role sync for that user entirely, to avoid conflicts. +- **Deleting SAML settings clears SCIM group assignments.** Using `DELETE /api/saml/settings` wipes all group assignment records and resets SCIM group settings for the organization. If you need to reconfigure SAML, re-save your SCIM settings afterward. +- **`manual_role_management` is shared.** The per-org override in SAML settings takes precedence over the billing/environment default for both SAML and SCIM role removal behavior. +- **SSO login can still change roles even with SCIM.** If a user authenticates via SAML and SAML role mappings are configured, the role may be re-evaluated on login based on SAML group attributes---potentially overriding a role set by SCIM. To avoid this, either use the same mappings in both, or configure role mappings in only one of the two. + +For more information on SCIM setup, see [Set up SCIM2 for Label Studio](scim_setup.html). ## Manage user access only with SSO @@ -139,6 +269,15 @@ MANUAL_ROLE_MANAGEMENT=0 Setting these options disables the Label Studio API and UI options to assign roles and workspaces for specific users within Label Studio and relies entirely on the settings in the environment variable file. +| Flag | Scope | Default | Effect when disabled (`0` / `False`) | +| --- | --- | --- | --- | +| `MANUAL_ROLE_MANAGEMENT` | Org roles | `True` (manual allowed) | Org roles are managed exclusively by SAML/SCIM. Users removed from all role groups are set to Deactivated. Overridable per-org in SAML settings. | +| `MANUAL_WORKSPACE_MANAGEMENT` | Workspaces | `True` (manual allowed) | Workspace membership is managed exclusively by SAML/SCIM. On each SAML login, workspaces are fully re-synced from groups. SCIM removes workspace memberships when users leave groups. | +| `MANUAL_PROJECT_MEMBER_MANAGEMENT` | Projects | `True` (manual allowed) | Project membership is managed exclusively by SAML/SCIM. Project memberships are removed when users leave groups. | + +!!! note + The `manual_role_management` flag has a per-organization override in SAML settings (`SamlSettings.manual_role_management`). When set, the SAML override takes precedence over the environment/billing default for both SAML and SCIM role removal behavior. + !!! info Tip If you are using the SaaS version of Label Studio (Label Studio Enterprise Cloud) and would like to enable these restrictions for your organization, [open a ticket](https://support.humansignal.com/hc/en-us/requests/new) to submit your request. @@ -146,4 +285,48 @@ Setting these options disables the Label Studio API and UI options to assign rol ### Login page URL -You can also set the `LOGIN_PAGE_URL` environment variable to redirect the login page to the specified URL. \ No newline at end of file +You can also set the `LOGIN_PAGE_URL` environment variable to redirect the login page to the specified URL. + +## Troubleshooting SAML SSO + +### SSO login redirects to an error page + +- Verify the **ACS URL** in your IdP matches exactly what Label Studio shows in SSO & SAML settings. +- Verify the IdP metadata (URL or XML) is correctly configured in Label Studio. +- Check that the **domain** in Label Studio SAML settings matches the user's email domain. +- Ensure the user is assigned to the Enterprise Application in your IdP. + +### User created with wrong role after SSO login + +- Verify the `mapping_groups` attribute name matches what your IdP sends (check the SAML assertion). +- For Entra ID: ensure it sends **group names** (not Object IDs) in the groups claim. +- Verify the group name in your IdP exactly matches (case-sensitive) the name in Label Studio SAML settings. +- If using both SAML and SCIM with different role mappings, the last one to run wins. + +### Attributes not being extracted from SAML assertion + +- Use a SAML debugging tool (e.g. browser extension) to inspect the raw assertion and confirm attribute names. +- Label Studio auto-detects attribute name format (URI vs short name) from metadata, but may not always match. Configure `mapping_email`, `mapping_first_name`, etc. explicitly if auto-detection fails. +- Entra ID full URI attribute names are case-sensitive. + +### Email case mismatches + +Label Studio normalizes all emails to lowercase for both SAML and SCIM operations. `Alice@Contoso.com` and `alice@contoso.com` are treated as the same user. No special configuration is needed. + +### Group name mismatches + +Group name matching in SAML settings is **case-sensitive**. `LS-Admins` and `ls-admins` are treated as different groups. Ensure exact casing matches between your IdP group names and Label Studio mapping configurations. + + +## Advanced SAML configuration + +For advanced SAML configuration, the following environment variables control pysaml2 SP behavior: + +| Variable | Default | Description | +| --- | --- | --- | +| `SAML_ALLOW_UNSOLICITED` | (pysaml2 default) | Accept IdP-initiated SSO | +| `SAML_AUTHN_REQUESTS_SIGNED` | (pysaml2 default) | Sign authentication requests | +| `SAML_WANT_ASSERTIONS_SIGNED` | (pysaml2 default) | Require signed assertions | +| `SAML_WANT_RESPONSE_SIGNED` | (pysaml2 default) | Require signed responses | +| `SAML_WANT_ASSERTIONS_OR_RESPONSE_SIGNED` | (pysaml2 default) | Require at least one signed | +| `DISABLE_SAML_SSL_VALIDATION` | (not set) | Disable SSL cert validation for metadata fetch | diff --git a/docs/source/guide/scim_setup.md b/docs/source/guide/scim_setup.md index e156cd7230d6..a7c34b2223f5 100644 --- a/docs/source/guide/scim_setup.md +++ b/docs/source/guide/scim_setup.md @@ -31,7 +31,7 @@ For more information on SCIM workflows, see [How SCIM works with Label Studio En !!! note Okta or similar SSO providers have SCIM integration based on SSO. -* You will need to provide a [Legacy token](access_tokens#Legacy-tokens), and it must be associated with the Owner role of your organization. +* You will need a Label Studio API token from the organization owner. Both [Legacy tokens](access_tokens#Legacy-tokens) and JWT-based Personal Access Tokens (PATs) are supported. ## Set up SCIM integration with Okta @@ -151,45 +151,246 @@ To unassign a group from the application, follow the steps for [Unassigning the ## Set up SCIM with Microsoft Entra ID (Azure AD) -Label Studio Enterprise supports SCIM provisioning with Microsoft Entra ID (formerly Azure AD). The setup is similar to Okta, but requires specific attribute mapping configuration. +Label Studio Enterprise supports SCIM provisioning with Microsoft Entra ID (formerly Azure AD). You can use the same Enterprise Application created for SAML SSO, or create a separate one for SCIM provisioning. Using the same application is simpler when you want both SSO and provisioning. -### Supported user attributes +### Step 1: Create or reuse the Enterprise Application -Label Studio Enterprise supports a limited set of SCIM user attributes for provisioning. When configuring attribute mappings in Microsoft Entra ID, only include the attributes listed below. +If creating a new application specifically for SCIM: -| SCIM Attribute | Description | Required | -|---|---|---| -| `emails[type eq "work"].value` | User's email address (primary identifier) | Yes | -| `userName` | Username (mapped to email in Label Studio) | Yes | -| `active` | Whether the user is active | Yes | -| `name.givenName` | User's first name | No | -| `name.familyName` | User's last name | No | +1. In the Azure Portal, go to **Entra ID → Enterprise Applications → New Application**. +2. Select **Create your own application** → **Integrate any other application not found in the gallery**. +3. Name it (e.g. `Label Studio SCIM`) and create it. + +### Step 2: Enable provisioning + +1. Open your Enterprise Application → **Provisioning** → **Get started**. +2. Set **Provisioning Mode** to **Automatic**. +3. Under **Admin Credentials**: + - **Tenant URL**: `https:///scim/v2` (both `/scim/v2` and `/scim/` are accepted) + - **Secret Token**: A Label Studio API token from the organization owner (legacy token or PAT) +4. Click **Test Connection** to verify connectivity. +5. Click **Save**. + +### Step 3: Configure user attribute mappings + +Go to **Provisioning → Mappings → Provision Microsoft Entra ID Users**. + +#### Required mappings + +| Entra ID Attribute | SCIM Target Attribute | Required | Notes | +| --- | --- | --- | --- | +| `userPrincipalName` | `userName` | **Yes** | Must be a valid email address. Label Studio uses this as the user's email and login identifier. If your UPNs are not email addresses, map `mail` instead. | +| `Switch([IsSoftDeleted], , "False", "True", "True", "False")` | `active` | **Yes** | Controls user activation/deactivation. When set to `false`, the user's org role becomes **Deactivated**. | + +#### Recommended mappings + +| Entra ID Attribute | SCIM Target Attribute | Required | Notes | +| --- | --- | --- | --- | +| `givenName` | `name.givenName` | No | First name, displayed in the Label Studio UI. | +| `surname` | `name.familyName` | No | Last name, displayed in the Label Studio UI. | + +#### Optional mappings (no effect) + +These attributes are accepted by the SCIM endpoint but have no functional impact in Label Studio: + +| Entra ID Attribute | SCIM Target Attribute | Notes | +| --- | --- | --- | +| `objectId` | `externalId` | Ignored on write---Label Studio always returns the user's email as `externalId` regardless of the inbound value. | +| `displayName` | `displayName` | Read-only in Label Studio; always derived from `first_name + last_name`. | +| `preferredLanguage` | `locale` | Ignored; always returns `en-US`. | + +#### Mappings to remove !!! warning "Unsupported attributes cause provisioning errors" - Mapping attributes that Label Studio does not support will result in **HTTP 501 (Not Implemented)** errors during SCIM provisioning. You must remove all excess Microsoft Entra ID attribute mappings like these: + Remove any default Entra ID mappings that target attributes not supported by Label Studio's SCIM endpoint. Leaving unsupported mappings in place will result in **HTTP 501 (Not Implemented)** errors during provisioning. Common mappings to remove: - * `displayName` - * `preferredLanguage` + * `mailNickname` + * `facsimileTelephoneNumber` + * `mobile` + * `physicalDeliveryOfficeName` + * `streetAddress`, `state`, `postalCode`, `country` * `name.formatted` - * `externalId` - -### Configure Microsoft Entra ID provisioning - -1. In the [Microsoft Entra admin center](https://entra.microsoft.com), select **Enterprise apps** in the left menu. -2. Select your enterprise application. -3. Select **Provisioning** in the left menu. -4. Set the **Tenant URL** to `https:///scim/v2/`. -5. Set the **Secret Token** to the [Legacy token](access_tokens#Legacy-tokens) associated with the Owner account in Label Studio. - - This must be the Legacy token, not the Personal Access Token. It must also be associated with the user in the Owner role. -6. Under **Mappings**, open **Provision Microsoft Entra ID Users**. -7. Remove all attribute mappings except the supported ones listed above. - - Keep: - * `emails[type eq "work"].value` → `userPrincipalName` - * `userName` → `userPrincipalName` - * `active` → `Switch([IsSoftDeleted], , "False", "True", "True", "False")` - * `name.givenName` → `givenName` - * `name.familyName` → `surname` -8. Under **Mappings**, open **Provision Microsoft Entra ID Groups** and ensure it is enabled if you want to use group-based role assignment. -9. For group provisioning, configure SCIM group settings in Label Studio (see [Set up group mapping](#set-up-group-mapping) above). + * Any `urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:*` attributes + +!!! note + Entra ID typically does **not** send the `emails` array in its SCIM payloads. Label Studio derives the email from `userName` when `emails` is absent, as long as `userName` is a valid email address. If your tenant's UPNs are not email addresses (e.g. `jsmith@contoso.local`), map `mail` to `userName` instead. + +### Step 4: Configure group provisioning + +Go to **Provisioning → Mappings → Provision Microsoft Entra ID Groups**. + +#### Required group mappings + +| Entra ID Attribute | SCIM Target Attribute | Required | Notes | +| --- | --- | --- | --- | +| `displayName` | `displayName` | **Yes** | The group name. This value must **exactly match** (case-sensitive) the group names configured in Label Studio's SCIM settings. | +| `members` | `members` | **Yes** | The list of group members. Entra ID sends member additions/removals as PATCH operations. | + +#### Assigning groups to the application + +Only groups that are **assigned to the Enterprise Application** in Entra ID will be provisioned: + +1. Go to **Enterprise Application → Users and groups → Add user/group**. +2. Select the security groups you want to provision. +3. Click **Assign**. + +The `displayName` of each assigned group is what Label Studio uses to match against its mapping rules. + +### Step 5: Configure SCIM group mappings in Label Studio + +This is where you tell Label Studio what each Entra ID group **means**---which role, workspace, or project access it grants. + +Configure mappings via the API: + +```bash +curl -X POST "https:///api/scim/settings" \ + -H "Authorization: Token " \ + -H "Content-Type: application/json" \ + -d '{ + "roles_groups": [ + ["Administrator", "LS-Admins"], + ["Manager", "LS-Managers"], + ["Reviewer", "LS-Reviewers"], + ["Annotator", "LS-Annotators"] + ], + "workspaces_groups": [ + ["Engineering", "LS-Engineering-Team"], + ["QA", "LS-QA-Team"] + ], + "projects_groups": [ + {"project_id": 42, "group": "LS-Project42-Annotators", "role": "Annotator"}, + {"project_id": 42, "group": "LS-Project42-Reviewers", "role": "Reviewer"}, + {"project_id": 99, "group": "LS-AllProjects", "role": "Inherit"} + ] + }' +``` + +Or configure them in the Label Studio UI under **Organization → SCIM Settings**. + +For detailed information on the mapping format and behavior, see [Group mapping reference](#group-mapping-reference) below. + +### Step 6: Start provisioning + +1. Go to **Provisioning → Overview**. +2. Click **Start provisioning**. +3. Entra ID will perform an initial sync cycle (can take 20--40 minutes for the first cycle). +4. Subsequent incremental syncs run approximately every 40 minutes. + +You can trigger an on-demand sync from the **Provision on demand** option for individual users. + + +## Group mapping reference + +Both SAML and SCIM use the same group mapping format and the same underlying mapping logic. The mapping types are configured independently for each protocol (SAML settings and SCIM settings are separate), but the behavior is identical. + +### Organization role mapping (`roles_groups`) + +Maps a group from your IdP to an organization-level role. + +**Format:** `["", ""]` + +**Available roles:** + +| Role Name | Description | +| --- | --- | +| `Administrator` | Full organization admin access | +| `Manager` | Can manage projects and members | +| `Reviewer` | Can review annotations | +| `Annotator` | Can annotate tasks | + +!!! note + `Owner` cannot be assigned via SAML or SCIM---it is explicitly excluded from group mappings. `Not Activated` and `Deactivated` are internal system states managed automatically and should not be used in `roles_groups` mappings. + +**Behavior when a user is in multiple role groups:** The most elevated role wins. For example, if a user is in both an Annotator group and a Manager group, they get the Manager role. + +**Behavior when a user is removed from all role groups:** Their role is set to Deactivated (subject to the `manual_role_management` flag). + +### Workspace mapping (`workspaces_groups`) + +Maps a group from your IdP to a Label Studio workspace. + +**Format:** `["", ""]` + +- Workspaces are **automatically created** when a SCIM group push or SAML login triggers the mapping. However, the `/api/scim/settings` endpoint validates that referenced workspaces already exist---create them first, or use the UI to save settings. +- A user can be mapped to multiple workspaces through multiple group memberships. +- **SCIM:** removal respects the `manual_workspace_management` billing flag---if enabled, users are not automatically removed from workspaces when they leave a group. +- **SAML:** workspace sync behavior is controlled by the `MANUAL_WORKSPACE_MANAGEMENT` environment variable (default: `True`). When `False`, all SAML-mapped workspaces are reset and re-applied on each login. + +### Project role mapping (`projects_groups`) + +Maps a group from your IdP to membership in a specific project, with a project-level role. + +**Format:** `{"project_id": , "group": "", "role": ""}` + +**Available project roles:** + +| Role | Description | +| --- | --- | +| `Inherit` | User gets project access but inherits their organization role (no explicit project role assigned) | +| `Annotator` | Explicit annotator role on the project | +| `Reviewer` | Explicit reviewer role on the project | + +- `project_id` must be an existing project in your organization. +- The most elevated role wins when a user is in multiple groups mapped to the same project. +- Removal respects the `manual_project_member_management` billing flag. +- **When SCIM project group assignments exist for a user, SAML project sync is skipped** for that user to avoid conflicts. + + +## SCIM user lifecycle + +| Event | What happens in Label Studio | +| --- | --- | +| **User provisioned** | Account created with the organization's default role (configured in Organization settings). Role is then updated when group sync runs. | +| **User already exists in another org** | User is added to this organization with the default role. Profile fields (name, etc.) are **not** overwritten---only the org membership is created. | +| **User added to a role group** | Role upgraded to the mapped role (or highest if in multiple groups). | +| **User removed from a role group** | Role falls back to the next-highest mapped role, or Deactivated if no role groups remain (subject to `manual_role_management`). | +| **User deactivated in Entra ID / Okta** | `active` set to `false` → role becomes Deactivated. | +| **User reactivated in Entra ID / Okta** | `active` set to `true` → role restored from SCIM group mappings, or the organization's default role if no mappings exist. | +| **User deleted in Entra ID / Okta** | Soft-deleted in Label Studio (deactivated, not removed). | + + +## SAML and SCIM interaction + +If your organization uses both SAML SSO and SCIM provisioning, be aware of the following interactions: + +- **Group mappings are configured separately.** SAML settings (`/api/saml/settings`) and SCIM settings (`/api/scim/settings`) each have their own `roles_groups`, `workspaces_groups`, and `projects_groups`. You can configure identical mappings in both, or use different mappings for each protocol. +- **SCIM project mappings take precedence over SAML.** When SCIM-driven project group assignments exist for a user, SAML skips its project role sync for that user entirely, to avoid conflicts. +- **Deleting SAML settings clears SCIM group assignments.** Using `DELETE /api/saml/settings` wipes all group assignment records and resets SCIM group settings for the organization. If you need to reconfigure SAML, re-save your SCIM settings afterward and wait for the next group sync to rebuild assignments. +- **`manual_role_management` is shared.** The per-org override in SAML settings takes precedence over the billing/environment default for both SAML and SCIM role removal behavior. +- **SSO login can still change roles even with SCIM.** If a user authenticates via SAML and SAML role mappings are configured, the role may be re-evaluated on login based on SAML group attributes---potentially overriding a role set by SCIM. To avoid this, either use the same mappings in both, or configure role mappings in only one of the two. + +For more information on SAML SSO setup, see [Set up SSO authentication for Label Studio](auth_setup.html). + + +## Troubleshooting + +### Provisioning test connection fails + +- Verify the SCIM endpoint URL ends with `/scim/v2` (or `/scim/`). +- Verify the bearer token belongs to the **organization owner** (SCIM API requires owner-level authentication). Both legacy API tokens and PATs are accepted. +- Check that the Label Studio instance is reachable from the internet (or via your network configuration). + +### User created but has wrong role + +1. Verify the user is assigned to the correct group in your IdP. +2. Verify the group is assigned to the Enterprise Application (in Entra ID) or pushed to the application (in Okta). +3. Verify the group `displayName` in your IdP exactly matches (case-sensitive) the name in Label Studio SCIM settings. +4. Ensure a provisioning cycle has completed after the group assignment (or trigger on-demand provisioning). + +### Users not appearing in workspaces or projects + +- Group provisioning must be enabled in the attribute mappings. +- The group must be **assigned** to the Enterprise Application (just existing in Entra ID is not enough). +- SCIM group settings in Label Studio must be configured **before** or **at the same time as** the groups are pushed. If settings are configured after groups were already synced, save the SCIM settings again to trigger re-evaluation. + +### Unsupported attribute errors in provisioning logs + +Remove any default IdP attribute mappings that target attributes not in the Label Studio SCIM schema. See the [Mappings to remove](#mappings-to-remove) section above for common attributes to remove. + +### Email case mismatches + +Label Studio normalizes all emails to lowercase for both SAML and SCIM operations. `Alice@Contoso.com` and `alice@contoso.com` are treated as the same user. No special configuration is needed. + +### Group name mismatches + +Group name matching in SCIM settings is **case-sensitive**. `LS-Admins` and `ls-admins` are treated as different groups. Ensure exact casing matches between your IdP group names and Label Studio mapping configurations.