Skip to content

Fixes #35674: sync SSO display name and picture on server-side OIDC logins - #35675

Queued
mohityadav766 wants to merge 5 commits into
mainfrom
fix/sso-profile-picture-display-name
Queued

mohityadav766 wants to merge 5 commits into
mainfrom
fix/sso-profile-picture-display-name

Conversation

@mohityadav766

@mohityadav766 mohityadav766 commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

Describe your changes:

Fixes #35674

With SSO set up as a confidential (server-side) OIDC client, signed-in users got neither a profile picture nor a display name from the identity provider: the avatar showed an initial, and the name shown was the login name. On that flow the server completes sign-in, so the server has to apply the provider's profile claims. It applied neither:

  • Display name — a regression since 1.12.4. On the default principal-claims path (emailClaim unset), OidcIdentityResolver resolves the provider's name (name, or given_name + family_name) and getOrCreateOidcUser dropped it. feat(ui): support displayName extraction from user when login #25623 added the sync. Mcp oauth #25391 (MCP OAuth) removed it while merging over it, and its cherry-pick took it out of 1.12.4. 1.11.10–1.12.3 had it; 1.12.4+, 1.13.x, 2.0.x and main don't.
  • Picture — never implemented for this flow. No server code read the standard OIDC picture claim, and the callback page hands the browser picture: ''. Only public clients, where the browser PATCHes the user, got pictures.
  • The browser stamped the username. After a server-driven login, checkIfUpdateRequired saved the name redirect parameter, which is the OpenMetadata username, as the display name when the account had none.
  • A login could erase the stored profile. The principal-claims path loaded the user with id,roles,teams only and PUT that copy back when a login promoted an admin or assigned a team from claims, which createOrUpdate records as deleting profile and the other fields the lookup left out (see UserRepository.getAuthUpdateFields()).

This PR:

  • Backend
    • OidcIdentityResolver.ResolvedOidcIdentity gains picture: the picture claim, parsed once and kept only when it is an absolute http/https URI, because it ends up as an image source in the browser.
    • New UserProfileClaims:
      • syncPicture stores the picture as profile.images.image. A new picture replaces the whole image list, so sizes derived from an older picture stop showing. A token without a picture never clears the stored one.
      • fillDisplayName fills the display name when the account has none, or has one that only repeats its login name. A name chosen in OpenMetadata is kept.
    • AuthenticationCodeFlowHandler: both OIDC paths store the picture. The email-first path does it through the provisioner's OIDC mutators, which already assigned teams; it already synced the display name. The principal-claims path applies the display name again, on sign-up and on login.
    • New UserRepository.getUserByNameForAuthUpdate(name), the name counterpart of getActiveUserByEmailForAuth: the principal-claims path now loads the account fresh with getAuthUpdateFields(), so saving it can't erase fields.
  • UI
    • New isServerDrivenLogin(clientType, provider): a confidential client or SAML, the same condition that already picks GenericAuthenticator. handleSuccessfulLogin skips checkIfUpdateRequired for those logins. Public OIDC clients are unchanged.
  • Decision record: docs/decisions/2026-10-17-the-server-applies-the-sso-profile-on-server-driven-logins.md.

Existing accounts: a user whose display name was stamped with their login name gets the provider's name on their next sign-in, with no migration.

Type of change:

  • Bug fix

High-level design:

  • Approach: whenever the server completes sign-in, it owns the SSO profile. The resolver converts the token claims once into the typed ResolvedOidcIdentity, and a small pure helper, UserProfileClaims, applies them to a User, so the rules are unit-tested on real User objects.
  • Alternatives rejected:
    • Reading the claims in the browser on the confidential path. Since Fixes #32000, #33553: Hand confidential OIDC browsers the identity provider's ID token #34967 the browser holds the provider's own ID token, so it would work for OIDC, but SAML gets an OpenMetadata-issued token, and it leaves two writers for the same fields.
    • Giving the principal-claims path the email-first rule, where the provider's name always replaces the stored one. That overwrites display names users chose. The decision record says what revisiting it means.
    • Generating Google-style sized variants (=s512-c) on the server. That's provider-specific, and the UI's image fallback chain already ends at image.
  • Backward compatibility: no schema, API or migration change. Public OIDC clients keep the browser-side sync. Azure AD issues no picture claim, so Azure users still get no picture.
  • Not changed here: after a Basic or LDAP login the browser still derives a display name from the email when the account has none. Those logins keep their own authenticator, so they're outside isServerDrivenLogin.

Tests:

Use cases covered

  • Confidential OIDC, principal-claims path:
    • a new user gets the provider's display name and picture;
    • an existing user with no display name, or one equal to the login name, gets the provider's name; a chosen one is kept;
    • a login that promotes an admin keeps the stored profile.
  • Confidential OIDC, email-first path: a new and an existing user get the provider's picture.
  • A new picture replaces every stored size; a token without a picture keeps the stored one; javascript:, data:, file: and relative values are ignored.
  • After a confidential-client login the UI doesn't write the profile; after a public-client login it still does.

Unit tests

  • I added unit tests for the new/changed logic.
  • UserProfileClaimsTest (new, 21 cases), OidcIdentityResolverTest (+1), AuthenticationCodeFlowHandlerTest (+5).
    • Four of them failed on main's behaviour before the fix: expected: <Jane Doe> but was: <null> on sign-up, nothing persisted for an existing user (principal-claims and email-first), and Saving the login's changes erased the stored profile.
  • UI: AuthProvider.util.test.ts (+4, isServerDrivenLogin), AuthProvider.test.tsx (+2). The confidential-client test fails against main's AuthProvider.tsx: checkIfUpdateRequired received {"profile": {"email": "aaron@example.com", "name": "aaron"}}.
  • The related suites pass too: AuthProviderUtil.test.ts, UserDataUtils.test.ts, SamlCallback.test.tsx (113 tests across the 5 suites).
  • Coverage on changed lines: Java 51/53 executable lines (jacoco; the uncovered ones are the one-line dispatch inside the full OIDC callback, which unit tests don't drive). UI 11/11 statements (Jest).

Backend integration tests

  • I added integration tests in openmetadata-integration-tests/ for the changed behaviour.
  • EmailFirstIdentityIT, against the real repository:
    • testSignInStoresAndRefreshesTheProviderPicture: sign-up stores the picture, a new one replaces it, a token without one keeps it;
    • testLoginByNameDoesNotEraseStoredUserFields: the principal-claims lookup loads the stored profile, and saving that copy after the login fills the display name keeps it.

Local Java test run: PASSED

  • Commit: eaa97997d226 (base origin/main)
  • Finished: 2026-10-17 09:19 UTC · 12.0 min
  • Details: the classes each step ran, why these tests, the commands
Step Scope Classes Tests Failed Skipped Min Result
unit openmetadata-mcp (1 class), openmetadata-service (26 classes) 27 582 0 0 1.1 passed
integration mysql-elasticsearch · parallel 63 3285 0 289 3.9 passed
integration mysql-elasticsearch · isolated 2 18 0 0 2.4 passed
integration mysql-elasticsearch · rdf 2 14 0 0 2.1 passed
integration cache-tests · isolated 2 11 0 0 2.5 passed
  • Impacted, not run locally: 2 classes (listed in the details)

Ingestion integration tests

  • Not applicable (no ingestion changes).

Playwright (UI) tests

  • Not applicable to the changed branch. make playwright_affected selects 43 specs, all of which sign in with basic auth, where isServerDrivenLogin is false and the login path is unchanged; none reaches a confidential-client or SAML login. Not run locally; the merge queue runs the full suite. The SSO sign-in suites (GoogleSsoSignInUIIT, GoogleSsoBootstrapUIIT) run nightly and assert neither display name nor picture.

Manual testing performed

Not run against a live SSO deployment; the integration tests above cover persistence. To reproduce by hand:

  1. Configure an OIDC provider that issues name and picture for the profile scope (Google, Auth0, or a Keycloak user with a picture), with clientType: confidential and emailClaim unset.
  2. Sign in as a new user → the user menu shows the provider's name and picture; GET /api/v1/users/loggedInUser?fields=profile returns displayName and profile.images.image.
  3. Set an existing user's display name to their login name (PATCH /api/v1/users/{id}), sign in again → it becomes the provider's name. Set it to something else, sign in again → it is kept.

UI screen recording:

Not applicable — a bug fix, not a UI feature. The UI change only stops the browser from writing the profile after a confidential-client or SAML login; the avatar renders the stored picture through the existing component.

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes <issue-number>: <short explanation>
  • My PR is linked to a GitHub issue via Fixes #<issue-number> above.
  • I have commented on my code, particularly in hard-to-understand areas.
  • For JSON Schema changes: not applicable (no schema change).
  • For a UI feature or feature task: not applicable (bug fix; see above).
  • I have added tests (unit / integration / Playwright as applicable) and listed them above.
  • Decision check: docs/decisions/2026-10-17-the-server-applies-the-sso-profile-on-server-driven-logins.md.
  • I have added a test that covers the exact scenario we are fixing (AuthenticationCodeFlowHandlerTest.getOrCreateOidcUser_*TheProviderAsserts, AuthProvider.test.tsx "leaves the profile to the server after a confidential-client login").

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no actionable issues were found.

Summary

The server now saves OIDC profile pictures and fills missing display names during confidential-client sign-in. The browser leaves server-driven profiles alone.

  • OIDC sign-ins save the provider’s picture and display name.
  • OIDC login updates keep the user’s stored profile and other fields.
  • Confidential OIDC and SAML logins skip browser profile updates.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[OIDC provider claims] --> B[Resolve identity and picture]
  B --> C[Load or create user]
  C --> D[Apply name and picture rules]
  D --> E[Save changed user]
  E --> F[Browser loads saved user]
  F --> G[Skip browser profile write]
  H[Public OIDC login] --> I[Keep browser profile update]
Loading

Reviews (2) · Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." · Reviewed by Greptile

On the confidential (server-side) OIDC flow the server signs the user in,
so it is the one that has to apply the identity provider's profile claims.
It applied neither:

- The legacy principal-claims path, which is the default while emailClaim
  is unset, resolved the provider's display name and then dropped it.
  #25391 removed the sync that #25623 had added, and every release since
  1.12.4 shipped without it.
- No path read the standard OIDC picture claim, so avatars only worked
  for public clients, where the browser saves them.

The browser made the name worse: after a server-driven login it saved the
username it was handed as the display name.

The OIDC resolver now reads the picture claim once, as an absolute http(s)
address, and both sign-in paths store it on the profile, replacing every
stored size when it changes. A token without a picture keeps the stored
one. The legacy path fills the display name when the account has none, or
has one that only repeats the username, so accounts the browser already
stamped are repaired on their next login; a name chosen in OpenMetadata is
kept.

The legacy path also loads the user with the auth-update field set.
Saving its "id,roles,teams" copy erased the stored profile whenever a
login promoted an admin or assigned a team.

The UI no longer writes the profile after a confidential-client or SAML
login.
…driven logins

Who writes the display name and picture after a confidential-client or SAML login, which picture addresses are stored, and when the legacy path may replace a display name.
getUserByNameForAuthUpdate is the name counterpart of getActiveUserByEmailForAuth: it reads the account fresh, with the auth-update fields a PUT of it writes back. With the lookup there, EmailFirstIdentityIT runs it against a real database and shows that the loaded copy carries the stored profile and that saving it keeps it.
@github-actions

Copy link
Copy Markdown
Contributor

❌ PR checklist incomplete

This PR cannot be merged until the following are addressed on its linked issue:

The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically.

Maintainers can bypass this check by adding the skip-pr-checks label.

@github-actions github-actions Bot added backend safe to test Add this label to run secure Github workflows on PRs labels Oct 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ UI Checkstyle passed — lint findings in changed files

🔍 ESLint findings in this PR's files — 0 error(s), 8 warning(s)

Errors block the build. Warnings do not yet — they are rules whose backlog is still
being worked down, listed so this PR does not add to it. See docs/ui-code-quality-gate.md.

0 error(s), 8 warning(s) across 1 changed file(s).

Count Rule
8 react-hooks/exhaustive-deps
All findings
Location Rule Message
🟡 src/components/Auth/AuthProviders/AuthProvider.tsx:345:9 react-hooks/exhaustive-deps The 'onLoginHandler' function makes the dependencies of useMemo Hook (at line 1213) change on every render. Move it inside the useMemo callback. Alternatively,
🟡 src/components/Auth/AuthProviders/AuthProvider.tsx:463:6 react-hooks/exhaustive-deps React Hook useCallback has missing dependencies: 'navigate', 'setApplicationLoading', 'setCurrentUser', and 'setIsAuthenticated'. Either include them or remove
🟡 src/components/Auth/AuthProviders/AuthProvider.tsx:549:9 react-hooks/exhaustive-deps The 'resetUserDetails' function makes the dependencies of useMemo Hook (at line 1213) change on every render. To fix this, wrap the definition of 'resetUserDeta
🟡 src/components/Auth/AuthProviders/AuthProvider.tsx:795:6 react-hooks/exhaustive-deps React Hook useEffect has missing dependencies: 'handleRefreshFailed', 'handleStoreProtectedRedirectPath', 'setIsAuthenticated', and 'signOutAfterRefreshFailure'
🟡 src/components/Auth/AuthProviders/AuthProvider.tsx:797:9 react-hooks/exhaustive-deps The 'handleFailedLogin' function makes the dependencies of useMemo Hook (at line 1213) change on every render. Move it inside the useMemo callback. Alternativel
🟡 src/components/Auth/AuthProviders/AuthProvider.tsx:868:5 react-hooks/exhaustive-deps React Hook useCallback has missing dependencies: 'handledVerifiedUser', 'navigate', and 'resetUserDetails'. Either include them or remove the dependency array.
🟡 src/components/Auth/AuthProviders/AuthProvider.tsx:919:9 react-hooks/exhaustive-deps The 'initializeAxiosInterceptors' function makes the dependencies of useMemo Hook (at line 1213) change on every render. To fix this, wrap the definition of 'in
🟡 src/components/Auth/AuthProviders/AuthProvider.tsx:1202:6 react-hooks/exhaustive-deps React Hook useEffect has a missing dependency: 'fetchAuthConfig'. Either include it or remove the dependency array.

Fix locally (fast - only checks files changed in this branch):

make ui-checkstyle-changed

@mohityadav766

mohityadav766 commented Oct 17, 2026 •

Copy link
Copy Markdown
Member Author

Local Java test run: PASSED — details

  • Commit: eaa97997d226 (base origin/main)
  • The summary is in the PR description.

Tests run locally

  • unit · openmetadata-mcp (1 class), openmetadata-service (26 classes): AuthCallbackServletTest (5 passed), AuthenticationCodeFlowHandlerTest (88 passed), BasicAuthServletHandlerTest (2 passed), CacheBundleTest (4 passed), CachedPermissionEvaluationTest (5 passed), DataContractPipelineTokenRefreshTest (6 passed), EntityCsvTest (67 passed), JwtFilterTest (55 passed), K8sPipelineClientBotTokenBugTest (2 passed), K8sPipelineClientTest (74 passed), LdapAuthServletHandlerTest (5 passed), LdapAuthenticatorTest (5 passed), McpCallbackServletTest (25 passed), OidcIdentityResolverTest (5 passed), OpenMetadataConnectionBuilderTest (5 passed), PermissionDebugServiceTest (6 passed), SamlAuthServletHandlerTest (21 passed), SetApprovalAssigneesImplTest (26 passed), SsoRedirectBoundaryTest (9 passed), SubjectCacheTest (20 passed), SubjectContextTest (11 passed), TestLoginServiceTest (22 passed), UserActivityTrackerTest (16 passed), UserMetricsServletTest (4 passed), UserProfileClaimsTest (26 passed), UserRepositoryUnitTest (2 passed), UserUtilTest (66 passed)
  • integration · mysql-elasticsearch · parallel: 63 classes, 2996 tests executed (listed below)
  • integration · mysql-elasticsearch · isolated: SessionMultiNodeIT (11 passed), UserMetricsResourceIT (7 passed)
  • integration · mysql-elasticsearch · rdf: RdfFusekiAuthorizationIT (9 passed), RdfPolicyRevocationIT (5 passed)
  • integration · cache-tests · isolated: SessionRedisMultiNodeIT (8 passed), TokenRevocationRedisMultiNodeIT (3 passed)

Per-class counts come from the test reports, which can credit a test to the wrong class when classes run concurrently, and keep only the last run of a nested class that several test classes inherit. The summary's step totals are Maven's own counts.

integration · mysql-elasticsearch · parallel: 64 classes

AIGovernancePolicyResourceIT (23 passed), ActivePersonaHeaderIT (41 passed, 6 skipped), AdminOnlyEndpointsIT (9 passed), AppMarketPlaceResourceIT (4 passed), AppOperationPermissionsIT (8 passed, 1 skipped), AppRunInterruptionIT (5 passed), AssetsTabAuthorizationIT (77 passed), BaseEntityIT$ListEntityHistoryByTimestampPaginationTest (31 passed, 4 skipped), BotImpersonationIT (4 passed), BotResourceIT (118 passed, 10 skipped), BulkOperationPermissionsIT (2 passed), ConfigResourceIT (13 passed), DataContractPermissionIT (47 passed, 2 skipped), DatabaseSmokeIT (1 passed), DomainAssetsColumnExclusionIT (3 passed), DomainBulkAssetsDryRunIT (83 passed, 6 skipped), DomainIsolationIT (25 passed, 3 skipped), DomainReassignmentAuthorizationIT (1 passed), DomainRecreateSameNameIT (23 passed, 3 skipped), DomainResourceIT (88 passed, 8 skipped), EmailFirstIdentityIT (42 passed, 2 skipped), FeedAccessAuthzIT (3 passed), GlossaryTermRelationSettingsPermissionsIT (24 passed, 1 skipped), GlossaryTermResourceIT (45 passed, 2 skipped), LoginLockoutIT (34 passed, 2 skipped), McpOAuthIT (11 passed), McpPermissionIT (167 passed, 23 skipped), MultiDomainHasDomainIT (25 passed, 2 skipped), MultiTeamUserFanOutIT (1 passed), OAuth2TokenManagerIT (17 passed, 1 skipped), PermissionsResourceIT (63 passed), PersonaAIContextIT (44 passed, 1 skipped), PersonaResourceIT (134 passed, 17 skipped), PipelineStatusAuthorizationIT (52 passed, 7 skipped), PolicyResourceIT (71 passed, 14 skipped), PolicyRevocationConcurrencyIT (184 passed, 27 skipped), ProviderRoleSyncIT (1 passed), QueryVisibilityPolicyIT (195 passed, 20 skipped), RoleResourceIT (40 passed, 3 skipped), SamlSecurityConfigIT (9 passed), SecurityServiceResourceIT (9 passed, 2 skipped), SeedDataPresenceIT (1 passed), ServiceAttributePolicyIT (87 passed, 9 skipped), SlackOAuth2AtRestEncryptionIT (5 passed), SubResourceAuthorizationIT (76 passed, 3 skipped), TableResourceIT (8 passed), TaskChangeEventIT (1 passed), TaskCommentsIT (27 passed), TaskFormSchemaResourceIT (45 passed, 6 skipped), TaskPermissionsIT (15 passed, 2 skipped), TaskResourceIT (65 passed, 5 skipped), TeamDefaultPersonaIT (10 passed), TeamHierarchyInheritanceIT (22 passed, 4 skipped), TeamResourceIT (18 passed, 2 skipped), TeamUserOwnsFanOutIT (2 passed), TestCaseCsvDomainIsolationIT (67 passed, 6 skipped), TestCaseResultAuthorizationIT (59 passed, 3 skipped), TestLoginSessionSweepIT (133 passed, 14 skipped), UserDefaultTeamAssignmentIT (1 passed), UserImportPrivilegeEscalationIT (56 passed, 2 skipped), UserPreferencesIT (55 passed, 12 skipped), UserResourceIT (34 passed, 2 skipped), UserTeamAssignmentPrivilegeIT (37 passed, 2 skipped), WorkflowTriggerPermissionsIT (192 passed, 27 skipped)

Why these tests
  • area security ← openmetadata-service/src/main/java/org/openmetadata/service/security/AuthenticationCodeFlowHandler.java, openmetadata-service/src/main/java/org/openmetadata/service/security/OidcIdentityResolver.java, openmetadata-service/src/main/java/org/openmetadata/service/security/UserProfileClaims.java
  • area teams-users ← openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/UserRepository.java
  • called from entity App ← openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/UserRepository.java
  • called from entity Bot ← openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/UserRepository.java
  • called from entity Domain ← openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/UserRepository.java
  • called from entity Task ← openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/UserRepository.java
  • called from entity User ← openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/UserRepository.java
  • changed test ← openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/EmailFirstIdentityIT.java, openmetadata-service/src/test/java/org/openmetadata/service/security/AuthenticationCodeFlowHandlerTest.java, openmetadata-service/src/test/java/org/openmetadata/service/security/OidcIdentityResolverTest.java, openmetadata-service/src/test/java/org/openmetadata/service/security/UserProfileClaimsTest.java
  • entity User ← openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/UserRepository.java
  • smoke ← code other than a test class changed
Impacted, not run locally (2)
  • GoogleSsoSignInUIIT → nightly: openmetadata-nightly k8s-java-it (ui-it + embedded JavaUIIT)
  • GoogleSsoBootstrapUIIT → nightly: openmetadata-nightly k8s-java-it (ui-it + embedded JavaUIIT)
Commands
mvn -B package -pl openmetadata-mcp,openmetadata-service -am -Dspring-boot.repackage.skip=true -Dtest=AuthCallbackServletTest,AuthenticationCodeFlowHandlerTest,BasicAuthServletHandlerTest,CacheBundleTest,CachedPermissionEvaluationTest,DataContractPipelineTokenRefreshTest,EntityCsvTest,JwtFilterTest,K8sPipelineClientBotTokenBugTest,K8sPipelineClientTest,LdapAuthServletHandlerTest,LdapAuthenticatorTest,McpCallbackServletTest,OidcIdentityResolverTest,OpenMetadataConnectionBuilderTest,PermissionDebugServiceTest,SamlAuthServletHandlerTest,SetApprovalAssigneesImplTest,SsoRedirectBoundaryTest,SubjectCacheTest,SubjectContextTest,TestLoginServiceTest,UserActivityTrackerTest,UserMetricsServletTest,UserProfileClaimsTest,UserRepositoryUnitTest,UserUtilTest -Dsurefire.failIfNoSpecifiedTests=false
mvn -B verify -pl :openmetadata-integration-tests -am -Dspring-boot.repackage.skip=true -Pmysql-elasticsearch -DintegrationTests.lane=parallel '-Dit.test=<63 classes>' -Dfailsafe.failIfNoSpecifiedTests=false -Dtest=NoUnitTestsInThisRun -Dsurefire.failIfNoSpecifiedTests=false
mvn -B verify -pl :openmetadata-integration-tests -am -Dspring-boot.repackage.skip=true -Pmysql-elasticsearch -DintegrationTests.lane=global-state -Dit.test=SessionMultiNodeIT,UserMetricsResourceIT -Dfailsafe.failIfNoSpecifiedTests=false -Dtest=NoUnitTestsInThisRun -Dsurefire.failIfNoSpecifiedTests=false
mvn -B verify -pl :openmetadata-integration-tests -am -Dspring-boot.repackage.skip=true -Pmysql-elasticsearch -DintegrationTests.lane=rdf -Dit.test=RdfFusekiAuthorizationIT,RdfPolicyRevocationIT -Dfailsafe.failIfNoSpecifiedTests=false -Dtest=NoUnitTestsInThisRun -Dsurefire.failIfNoSpecifiedTests=false
mvn -B verify -pl :openmetadata-integration-tests -am -Dspring-boot.repackage.skip=true -Pcache-tests -DintegrationTests.lane=global-state -Dit.test=SessionRedisMultiNodeIT,TokenRevocationRedisMultiNodeIT -Dfailsafe.failIfNoSpecifiedTests=false -Dtest=NoUnitTestsInThisRun -Dsurefire.failIfNoSpecifiedTests=false

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 78%
78.57% (129831/165242) 65.31% (82576/126419) 66.66% (27586/41380)

@mohityadav766 mohityadav766 self-assigned this Oct 17, 2026
@gitar-bot

gitar-bot Bot commented Oct 17, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

🟡 Medium risk · Server-driven logins now persist provider-supplied profile claims, so unexpected names or picture URLs could misrepresent users’ displayed identities.

Server-driven OIDC logins now persist the provider's display name and picture, fixing SSO users who saw an initial and their login name instead of their profile. The principal-claims lookup also loads the full user so login updates no longer erase stored profile fields, and the browser skips writing the profile after confidential-client and SAML logins. No issues found.

Verification

Rules No rules evaluated

Functional validation Not enabled

Set up

Auto-approval Not enabled

Set up

For more verification details, comment gitar display:verbose.

Options

Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

✅ SSO Login Nightly — PASSED

View workflow run · Commit ecf8f75

Provider Status Pass Fail Flaky Skip Duration
basic ✅ pass 28 0 0 0 6m 39s
ldap ✅ pass 7 0 0 0 1m 00s
keycloak-oidc-confidential ✅ pass 12 0 0 0 1m 38s
keycloak-oidc-public ✅ pass 11 0 0 0 1m 30s
msal-mock ✅ pass 7 0 0 0 0m 35s
auth0-mock ✅ pass 6 0 0 0 0m 37s
okta ⏩ skipped - - - - -
keycloak-azure-saml ✅ pass 23 0 0 0 5m 58s
keycloak-azure-saml-crosssite ⏩ skipped - - - - -

Totals: 94 passed · 0 failed · 0 flaky · 0 skipped · duration 18m 01s

@mohityadav766
mohityadav766 added this pull request to the merge queue Oct 17, 2026
Any commits made after this event will not be merged.

This branch was successfully deployed

1 active deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SSO profile picture and display name are not set for users signing in through a confidential OIDC client

3 participants