Repository navigation
Conversation
`oidc_group_claim` selects the JWT claim that group-to-role sync reads group names from. On the Frontegg authenticator that lookup ran against `Claims::unknown_claims`, the `#[serde(flatten)]` catch-all. Serde's flatten collects only the keys that no named field claimed, so the ten claims backed by a typed field on `Claims`, `roles` and `permissions` among them, never appear in that map and could not be selected at all. Setting `oidc_group_claim = 'roles'` was therefore accepted and then silently found nothing: extraction returned `None`, which `maybe_sync_jwt_groups` treats as "claim absent, skip sync", a branch that logs nothing and sends no notice. An operator gets no signal that the claim they chose is unreachable. The OIDC authenticator does not have this problem. `OidcClaims` types only `iss`, `exp`, `iat`, and `aud`, so every other claim lands in its flatten map and resolves normally. The same `oidc_group_claim` value consequently selected different claims under the two authenticators, which defeats the purpose of the shared `mz_auth::group_claims` extractor. Resolve the path against a JSON view of the whole `Claims` struct instead. The typed fields stay as they are, since `is_admin` reads `roles` directly, and nested paths such as `customClaims.groups` keep working. `roles` is now reachable generically rather than by a special case. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
mtabebe
approved these changes
Aug 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
oidc_group_claimselects which JWT claim group-to-role sync reads group names from. On the Frontegg authenticator, that lookup ran againstClaims::unknown_claims, the#[serde(flatten)]catch-all:Serde's
flattencollects only the keys that no named field claimed.Claimsdeclares ten named fields, sosub,exp,iss,type,email,userId,tenantId,roles,permissions, andmetadatanever appear in that map and could not be selected as the group claim at all, howeveroidc_group_claimwas set.rolesis the claim an operator is most likely to reach for. Frontegg emits it natively and populates it from group-to-role mappings, so mapping IdP groups to Frontegg roles and syncing those role names is the obvious configuration, and it needs no custom claim, no JWT prehook, and no group cache. Today that setting is accepted and then silently finds nothing: extraction returnsNone, whichmaybe_sync_jwt_groupstreats as "claim absent, skip sync". That branch logs nothing and sends no client notice, so there is no signal anywhere that the configured claim is unreachable.The OIDC authenticator does not have this problem.
OidcClaimstypes onlyiss,exp,iat, andaud, so every other claim lands in its flatten map and resolves normally,rolesincluded. The sameoidc_group_claimvalue therefore selected different claims depending on the authenticator, which defeats the purpose of routing both through the sharedmz_auth::group_claimsextractor.Change
Resolve the claim path against a JSON view of the whole
Claimsstruct rather than the flatten map alone.Claimsalready derivesSerializewithrename_all = "camelCase", so the reconstructed keys match the wire format.The typed fields are left in place,
is_adminreadsrolesdirectly. Nested untyped paths such ascustomClaims.groupskeep resolving exactly as before.rolesbecomes reachable generically, with no special case for it.Tests
Adds
groups_from_typed_roles_claimto thefrontegg-authunit tests, covering selection of a claim backed by a typed field. The existinggroups_absent_returns_none,groups_empty_returns_some_empty, andgroups_populated_returns_some_valuescases continue to cover the untyped paths.Release notes
This release will allow
oidc_group_claimto select any claim present in the JWT when using Frontegg authentication, includingroles. Previously, claims that Materialize parses into typed fields, such asrolesandpermissions, could not be used as the group claim, and configuring one caused group-to-role sync to be skipped without any error or notice.