Entra ID SSO: groups overage fallback always returns group object IDs, ignoring the claim's source attribute
Expected behavior
When Teleport resolves an Entra ID groups overage through Microsoft Graph, the resulting groups values should match what Entra ID emits for users who are under the group limit. If the enterprise application's group claim uses a source attribute other than Group ID (sAMAccountName, NetBIOSDomain\sAMAccountName, DNSDomainName\sAMAccountName, or cloud-only group display names), the overage path should return the same kind of value, so RBAC built on group names keeps working for every user regardless of how many groups they belong to.
Current behavior
Entra ID caps the number of groups in a token at 150 for SAML assertions and 200 for JWTs. Above the cap it omits the groups claim and emits an overage link instead (http://schemas.microsoft.com/claims/groups.link for SAML, _claim_names and _claim_sources for OIDC). Teleport Enterprise follows that link when credentials.oauth is set on the connector, as described in (Optional) Groups Overage.
The Graph lookup (IterateUsersTransitiveMemberOf in lib/msgraph) requests only $select=id, and the overage handler writes only the group object ID into the groups attribute. Nothing in the connector can change this: entra_id_groups_provider exposes disabled, group_type and graph_endpoint only.
As a result, a tenant that configured the group claim to emit sAMAccountName gets split behavior. Users under the cap log in with group names, users over the cap log in with object IDs. Login succeeds for both, but every piece of RBAC keyed on names silently stops matching for the second set of users. Examples: attributes_to_roles or claims_to_roles entries matching on a group name, role templates such as kubernetes_groups: ['{{external["http://schemas.microsoft.com/ws/2008/06/identity/claims/groups"]}}'], and Access List membership rules on the groups trait.
The overage fetch runs before the attributes are recorded in the user.login audit event, so the event shows both groups.link and a long list of object IDs under groups. That makes it look as if Entra ID emitted the IDs, which hides the actual cause. The docs sentence "fetch user's group details using the Microsoft Graph API" also does not say that only object IDs come back.
Bug details
- Recreation steps:
- Configure an Entra ID SAML or OIDC connector with
credentials.oauthso the groups overage path is active. - In the enterprise application, set the group claim's source attribute to
sAMAccountNameor cloud-only group display names. - Log in as a user with fewer than 150 groups. The
groupstrait contains names. - Log in as a user with more than 150 groups. The
groupstrait contains object IDs.
- Configure an Entra ID SAML or OIDC connector with
Workarounds
- Assign the relevant groups to the enterprise application and set the group claim to "Groups assigned to the application", so the emitted set stays under the cap and the overage never triggers. Nested groups are not included in this mode.
- Configure a group filter (prefix, suffix or contains on
sAMAccountNameor display name) under the group claim's advanced options. Entra ID applies the filter before the cap for users in 1000 or fewer groups. - Use a login rule to map known object IDs to names into a dedicated trait and point roles at that trait, so under-cap and over-cap users end up with the same values.
- Key RBAC on object IDs, which the Teleport Entra ID guide already recommends for
attributes_to_roles, at the cost of readability.
Related issues:
Source: gravitational/teleport