Fine-Grained Auth
SCIM group mapping
Use IdP groups as FGA user groups and optional authorization grants.
SCIM group sync feeds the same authorization model your application already uses. The identity provider is the SCIM client: it writes Group resources and membership to SqlOS. SqlOS mirrors those groups into FGA and can optionally map selected groups to roles on existing resources.
Every provisioned Group becomes an FGA user group:
| SCIM input | FGA result |
|---|---|
externalId | stable, connection-scoped source link |
displayName | mirrored group name |
members[].value | membership for the linked SqlOS user subject |
| Group rename | update the existing group rather than create a duplicate |
| Group deletion | remove directory-owned memberships and mapped grants; mark the external link inactive |
Mirroring does not grant a role by itself. It makes the directory group available to FGA grants, application access assignments, the dashboard, and the access tester.
Manage membership through Group.members; SqlOS does not accept User.groups as a writable attribute. Manual edits to a mirrored SCIM group's membership may be replaced by the next IdP PUT, PATCH, deactivation, or resync. Memberships in unrelated, non-SCIM FGA groups are not touched.
Group collections support only the exact reconciliation filters used by enterprise IdPs:
id eq "grp_123"
displayName eq "Acme-Admins"
externalId eq "00g123"The operator is eq; compound filters and operators such as co, sw, or pr return invalidFilter.
Group PUT and PATCH support:
displayNamemembers collectionmembers[value eq "{user-id}"]displayName or membersAdd a member:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "add",
"path": "members",
"value": [
{ "value": "usr_123" }
]
}
]
}Remove the same member:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "remove",
"path": "members[value eq \"usr_123\"]"
}
]
}Membership values may be the SqlOS SCIM User id or the user's external ID on the same connection. References from another connection or organization are not resolved. Adding an existing member or removing an absent member succeeds without creating duplicate state.
Most enterprise directory groups describe departments, mailing lists, or assignments—not application permissions. Automatically granting every synced group would create accidental access. SqlOS keeps the safe sequence explicit:
Unmatched groups remain available for deliberate manual grants and application assignments.
Use an exact mapping when the IdP group has a stable display name:
scim.MapGroup("Acme-Admins", mapping =>
{
mapping.RoleKey = "org_admin";
mapping.ResourceId = "organization::acme";
mapping.Description = "Directory-managed organization administrators";
});Use MapGroupExternalId instead when the provider's group ID is stable but administrators may rename its display name.
The resulting FGA grant uses the mirrored group subject, not one grant per user. FGA expands membership during access checks, so an IdP membership change updates authorization without rewriting each user's grants.
Use pattern mappings for a controlled family of resources:
scim.MapGroupPattern("^Store-(?<storeId>[^-]+)-Managers$", mapping =>
{
mapping.RoleKey = "store_manager";
mapping.ResourceIdTemplate = "store::{storeId}";
});For Store-123-Managers, the mapping resolves storeId to 123 and targets store::123.
Keep patterns anchored and narrow. SqlOS bounds regular-expression evaluation, but a broad pattern can still map an unintended group. The target role and resource must already exist; a mapping does not invent new authorization roots.
Managed-grant metadata records the connection, mapping, external group ID, FGA group, role, resource, and grant. SqlOS uses that ownership to revoke only the access it created when:
User membership changes do not delete the group grant. They add or remove the user's subject from the group, and FGA access changes through the existing group grant.
Changing or disabling a mapping immediately revokes the grants owned by that mapping. Disabling a connection immediately rejects its bearer token and revokes every managed grant owned by the connection. Mirrored groups, memberships, history, manual grants, non-SCIM groups, and unrelated FGA state remain intact.
Re-enabling a connection or mapping allows future provisioning but does not recreate revoked grants by itself. Push or resynchronize the affected groups after re-enabling so SqlOS can evaluate the current mapping and recreate the grants that should exist.
Manual grants and non-SCIM groups remain intact. Disabling or changing a mapping must not remove a grant that was not created and tracked by that mapping.
When the IdP sends active: false or deletes a User, SqlOS removes that user's memberships from the connection's mirrored groups and deactivates the user's organization membership. The person immediately loses group-derived access in that organization.
The same SqlOS user can still be active in another organization. SCIM does not remove that other tenant's membership, sessions, FGA groups, or grants. Bearer-token scope, external IDs, Group resources, and membership resolution all remain within one connection and organization.
The mapping editor shows the match mode, source group value, target role/resource, source (seeded or dashboard), enabled state, and active managed-grant count. Persisted sync events report missing roles and missing resources; patterns that exceed the bounded evaluation time are returned to the SCIM client as request errors.
A mirrored FGA group can also be assigned to a client application in selected_users_groups_roles mode:
{
"principalType": "group",
"principalId": "grp_acme_admins",
"access": "allowed"
}Application access and FGA permissions are separate decisions. The application assignment controls whether a user can use the client. The FGA grant controls what the user can do inside the application.
Query a group without changing it:
export SCIM_BASE_URL="https://app.example.com/sqlos/scim/v2"
export SCIM_TOKEN="paste-the-token-shown-by-sqlos"
curl --fail-with-body --silent --show-error --get \
-H "Authorization: Bearer $SCIM_TOKEN" \
-H "Accept: application/scim+json" \
--data-urlencode 'filter=displayName eq "Acme-Admins"' \
"$SCIM_BASE_URL/Groups"For repository validation, run the focused SCIM suite and docs gate:
dotnet test tests/SqlOS.Tests/SqlOS.Tests.csproj \
--filter 'FullyQualifiedName~SqlOSScim'
dotnet test tests/SqlOS.IntegrationTests/SqlOS.IntegrationTests.csproj \
--filter 'FullyQualifiedName~ScimProtocolIntegrationTests'
./scripts/docs-check.sh| Symptom | Check |
|---|---|
| IdP cannot find a group | Use one supported exact eq filter and confirm the token belongs to the group's organization |
Member add returns invalidValue | Provision the user first and send that connection's User id or externalId |
| Filtered remove fails | Use members[value eq "..."] with a User identifier, not User.groups |
| Group mirrors but no grant appears | Confirm the mapping is enabled and its role and target resource already exist |
| Rename creates unexpected authorization | Prefer an external-ID mapping when provider group names are mutable |
| Deprovisioned user still has access | Inspect non-SCIM groups, direct grants, application assignments, and memberships in other organizations |
| Mapping failure appears in sync events | Correct the role, resource, or template capture, then resend the group |
| Group request fails during pattern matching | Correct or simplify the pattern from the SCIM error response, then resend the group |
eq lookup works for ID, display name, and external IDinvalidValue