# SSO Group Role Mappings https://api-docs.lumar.io/docs/graphql/sso-group-role-mappings SSO group role mappings let your identity provider (IdP) decide what role each user has in your Lumar account. You map IdP group names to Lumar roles, and every time a user signs in through SSO, Lumar sets their role from the groups in their SAML assertion. Use them when you want role changes to happen in one place: add someone to a group in your IdP to promote them, remove them to demote them. ## Prerequisites - Your account has a SAML SSO connection. Check with `getSsoConnection`; it returns `null` when there is none. Lumar sets up and removes SSO connections for you, so contact your account manager or support to add one; account Admins can then change its settings with `updateSsoConnection`. - You have the **Admin** role in the Lumar account. Reading, creating, updating and deleting mappings all require it. - Your IdP sends the user's groups as an attribute in the SAML assertion. Most IdPs need this switched on in the SAML app's attribute statements (in Okta, a group attribute statement). ## How a user's role is chosen Once your account has at least one mapping, the role of every user signing in through your SSO connection is recalculated **on each sign-in**: 1. Lumar reads the group attribute from the SAML assertion. 2. Each group is compared against your mappings. Matching ignores case and surrounding whitespace, so `Lumar-Admins` in the assertion matches a mapping for `lumar-admins`. 3. If the user's groups match more than one mapping, the **highest** role wins. From highest to lowest: `Admin`, `Editor`, `Reporter`, `Viewer`. 4. If none of their groups match, they get the connection's `defaultRoleCode`, or `Viewer` when no default is set. This applies to new users on their first sign-in and to existing users every time after. A user removed from an elevated group in your IdP is demoted the next time they sign in. Mappings decide a user's **role**, not whether they can sign in. A user with no matching group still gets in with the fallback role. Control who can sign in by assigning the SAML app to users or groups in your IdP. ### Roles are managed by the IdP While your account has any mappings, the roles of SSO users can't be changed in Lumar. `updateAccountUser` that changes the `roleCode` of one of those users fails with `SSO_USER_ROLE_MANAGED_BY_SSO_GROUPS`. Change their groups in your IdP instead; the new role applies at their next sign-in. Users who don't sign in through your SSO connection are unaffected and keep the role you give them. ## Accounts that share a connection If your company has several Lumar accounts, one SSO connection can serve all of them. The connection belongs to one account, and the others share it. Admins of every account can read the connection with `getSsoConnection`. Its `ownedByAccount` field is `false` on the accounts that share it. Each account keeps its own settings: - Group role mappings, default role and group attribute name are set per account, so the same IdP group can map to different roles in different accounts. - An Admin of an account that shares the connection can change those settings for their own account with `updateSsoConnection` and the mapping mutations. - The SAML settings belong to the connection. Only an Admin of the account that owns it can change them; `updateSsoConnection` from another account fails with `SSO_CONNECTION_MANAGED_BY_ANOTHER_ACCOUNT` if it includes any of them. - The IP ranges also belong to the connection. Admins of every account can read them through `getSSOClientForAccount`, but only an Admin of the owning account can change them; `addSsoClientIpRange` and `removeSsoClientIpRange` from another account fail with `INSUFFICIENT_PERMISSIONS`. ## Step 1: Point Lumar at your group attribute By default Lumar reads the groups from an attribute named `groups`. If your IdP uses a different name (for example `memberOf`, or a full attribute URI), set `groupAttributeName` on the SSO connection. The attribute can carry a list of values or a single string with groups separated by `;`. This is also where you set the fallback role for users who match no mapping: ```graphql mutation UpdateSsoConnectionGroupAttribute($input: UpdateSsoConnectionInput!) { updateSsoConnection(input: $input) { ssoConnection { connectionName groupAttributeName defaultRoleCode } } } ``` **Variables:** ```json { "input": { "accountId": "TjAwN0FjY291bnQ3MTU", "groupAttributeName": "memberOf", "defaultRoleCode": "Viewer" } } ``` **Response:** ```json { "data": { "updateSsoConnection": { "ssoConnection": { "connectionName": "acme-okta", "groupAttributeName": "memberOf", "defaultRoleCode": "Viewer" } } } } ``` Setting `groupAttributeName` alone changes nothing: group-driven roles only start once the first mapping exists. Passing `null` resets it to `groups`. ## Step 2: Create mappings Create one mapping per IdP group you want to grant a role. Group names are stored trimmed and lowercased, and each group can be mapped once per account; mapping the same group a second time fails with a unique-constraint error. ```graphql mutation CreateAccountSsoGroupRoleMapping($input: CreateAccountSsoGroupRoleMappingInput!) { createAccountSsoGroupRoleMapping(input: $input) { accountSsoGroupRoleMapping { id ssoGroupName roleCode createdAt } } } ``` **Variables:** ```json { "input": { "accountId": "TjAwN0FjY291bnQ3MTU", "ssoGroupName": "Lumar-SEO-Editors", "roleCode": "Editor" } } ``` **Response:** ```json { "data": { "createAccountSsoGroupRoleMapping": { "accountSsoGroupRoleMapping": { "id": "TjAyNkFjY291bnRTc29Hcm91cFJvbGVNYXBwaW5nMQ", "ssoGroupName": "lumar-seo-editors", "roleCode": "Editor", "createdAt": "2026-10-28T10:00:00.000Z" } } } } ``` :::caution The first mapping switches group-driven roles on for the whole account. From the next sign-in, every SSO user whose groups match no mapping drops to `defaultRoleCode` (or `Viewer`), including existing Admins. Create the mapping for your admin group first, or set up all your mappings before your users next sign in. ::: ## List mappings Mappings are on the `ssoGroupRoleMappings` connection of the account. It supports the usual [pagination](/docs/graphql/pagination.md), [filtering](/docs/graphql/filtering.md) and [sorting](/docs/graphql/sorting.md) arguments, and can be filtered and sorted by `ssoGroupName`, `roleCode`, `createdAt` and `updatedAt`. ```graphql query GetSsoGroupRoleMappings($accountId: ObjectID!) { getAccount(id: $accountId) { id ssoGroupRoleMappings(first: 100, orderBy: [{ field: ssoGroupName, direction: ASC }]) { totalCount nodes { id ssoGroupName roleCode updatedAt } pageInfo { hasNextPage endCursor } } } } ``` **Variables:** ```json { "accountId": "TjAwN0FjY291bnQ3MTU" } ``` **Response:** ```json { "data": { "getAccount": { "id": "TjAwN0FjY291bnQ3MTU", "ssoGroupRoleMappings": { "totalCount": 3, "nodes": [ { "id": "TjAyNkFjY291bnRTc29Hcm91cFJvbGVNYXBwaW5nMg", "ssoGroupName": "lumar-admins", "roleCode": "Admin", "updatedAt": "2026-10-28T10:00:00.000Z" }, { "id": "TjAyNkFjY291bnRTc29Hcm91cFJvbGVNYXBwaW5nMw", "ssoGroupName": "lumar-reporting", "roleCode": "Reporter", "updatedAt": "2026-10-28T10:00:00.000Z" }, { "id": "TjAyNkFjY291bnRTc29Hcm91cFJvbGVNYXBwaW5nMQ", "ssoGroupName": "lumar-seo-editors", "roleCode": "Editor", "updatedAt": "2026-10-28T10:00:00.000Z" } ], "pageInfo": { "hasNextPage": false, "endCursor": "Mw" } } } } } ``` ## Update a mapping Change the group name, the role, or both. Fields you omit, or pass as `null`, keep their current value. ```graphql mutation UpdateAccountSsoGroupRoleMapping($input: UpdateAccountSsoGroupRoleMappingInput!) { updateAccountSsoGroupRoleMapping(input: $input) { accountSsoGroupRoleMapping { id ssoGroupName roleCode updatedAt } } } ``` **Variables:** ```json { "input": { "id": "TjAyNkFjY291bnRTc29Hcm91cFJvbGVNYXBwaW5nMQ", "roleCode": "Reporter" } } ``` **Response:** ```json { "data": { "updateAccountSsoGroupRoleMapping": { "accountSsoGroupRoleMapping": { "id": "TjAyNkFjY291bnRTc29Hcm91cFJvbGVNYXBwaW5nMQ", "ssoGroupName": "lumar-seo-editors", "roleCode": "Reporter", "updatedAt": "2026-10-28T11:30:00.000Z" } } } } ``` ## Delete a mapping ```graphql mutation DeleteAccountSsoGroupRoleMapping($input: DeleteAccountSsoGroupRoleMappingInput!) { deleteAccountSsoGroupRoleMapping(input: $input) { accountSsoGroupRoleMapping { ssoGroupName roleCode } } } ``` **Variables:** ```json { "input": { "id": "TjAyNkFjY291bnRTc29Hcm91cFJvbGVNYXBwaW5nMQ" } } ``` **Response:** ```json { "data": { "deleteAccountSsoGroupRoleMapping": { "accountSsoGroupRoleMapping": { "ssoGroupName": "lumar-seo-editors", "roleCode": "Reporter" } } } } ``` Deleting the **last** mapping turns group-driven roles off. Users keep the role they had at their last sign-in, and you can again change SSO users' roles in Lumar with `updateAccountUser`. ## Limits and troubleshooting - **One connection per account.** Mappings belong to the account and apply to its SSO connection. - **Changes apply at sign-in.** Lumar doesn't sync roles in the background. A group change in your IdP, or a mapping change in Lumar, takes effect when each user next signs in. - **Assertion size.** If the attributes in a SAML assertion exceed 64 KB, Lumar can't read the full group list, and sign-in is refused for accounts with mappings rather than risk assigning the wrong role. If your users belong to many groups, configure your IdP to send only the groups relevant to Lumar (in Okta, use a group filter on the attribute statement). - **Everyone lands on the fallback role.** Usually the group attribute is missing from the assertion or has a different name. Check the attribute name in your IdP's SAML app against `groupAttributeName`, and check that the group names in your mappings match what the IdP sends.