Skip to content

Abc/auth login#7

Merged
aristachauhan merged 4 commits into
mainfrom
abc/auth-login
Jul 6, 2026
Merged

Abc/auth login#7
aristachauhan merged 4 commits into
mainfrom
abc/auth-login

Conversation

@aristachauhan

@aristachauhan aristachauhan commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Basic authorization functionality for admins.

Summary by CodeRabbit

  • New Features
    • Added an authenticated Admin page with access checks and server status messaging.
    • Introduced an authenticated shell layout that shows Admin navigation only for admin users.
    • Added a local development login screen accessible via the About page.
    • Added an Admin status API endpoint.
  • Bug Fixes
    • Improved login and return-URL handling with stronger URL sanitization.
    • Improved authenticated user loading to be more resilient when claims are incomplete.
    • Updated the current-user response to include Entra object ID and reliably return roles (empty when missing).

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds admin assignment persistence, server-side user provisioning and role checks, a new admin status endpoint, an anonymous dev-login flow, and client-side authenticated/admin navigation plus dev-login UI.

Changes

Admin Authorization Feature

Layer / File(s) Summary
Admin assignment schema
server.core/Domain/AppAdminAssignment.cs, server.core/Domain/AppUser.cs, server.core/Data/AppDbContext.cs, server.core/Migrations/*
Adds the AppAdminAssignment entity, wires its DbSet and configuration into AppDbContext, and updates EF migrations and the model snapshot for the new table and AppUser navigation.
Claims and user provisioning
server/Helpers/ClaimsPrinciplesExtensions.cs, server/Services/UserService.cs, server/Helpers/AuthenticationHelper.cs, server/Program.cs, server/appsettings.json
Adds claims helpers, provisions user profiles and admin roles from claims and assignments, updates authentication hooks to use the new profile flow, registers AdminOnly, and sets the auth client ID.
Login and user API endpoints
server/Controllers/AccountController.cs, server/Controllers/AdminController.cs, server/Controllers/UserController.cs
Reworks /login for dev personas and return-url handling, adds an admin status endpoint, and changes /api/user/me to return the updated user shape and role list.
Client admin route and dev-login UI
client/src/queries/user.ts, client/src/routeTree.gen.ts, client/src/routes/(authenticated)/admin.tsx, client/src/routes/(authenticated)/route.tsx, client/src/shared/auth/AuthenticatedShell.tsx, client/src/routes/about.tsx
Updates the user query normalization, adds generated router metadata and a guarded /admin route, wraps authenticated pages in a shell, and adds the dev-login About page branch and persona links.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant AccountController
  participant OpenIdConnect
  participant AuthenticationHelper
  participant UserService
  participant AppDbContext

  Browser->>AccountController: GET /login?returnUrl&as
  AccountController->>AccountController: NormalizeReturnUrl / IsDevLoopback
  alt normal login
    AccountController->>OpenIdConnect: Challenge(RedirectUri=safeReturnUrl)
  else dev persona
    AccountController->>AccountController: SignInAsDevPersona(...)
    AccountController-->>Browser: redirect to safeReturnUrl
  end
  OpenIdConnect-->>AuthenticationHelper: OnTokenValidated(principal)
  AuthenticationHelper->>UserService: EnsureUserProfileAsync(principal, recordSignIn:true)
  UserService->>AppDbContext: load/create AppUser by EntraObjectId
  UserService->>AppDbContext: resolve roles from AppAdminAssignments
Loading
sequenceDiagram
  participant Browser
  participant AdminRoute
  participant UserController
  participant AdminController
  participant AuthenticatedShell

  Browser->>AdminRoute: navigate /admin
  AdminRoute->>UserController: GET /api/user/me
  UserController-->>AdminRoute: UserResponse
  AdminRoute->>AdminRoute: hasAdminRole(user)
  alt admin
    AdminRoute->>AdminController: GET /api/admin/status
    AdminController-->>AdminRoute: AdminStatusResponse
    AdminRoute->>AuthenticatedShell: render admin page inside shell
  else not admin
    AdminRoute-->>Browser: redirect to /
  end
Loading

Possibly related PRs

  • ucdavis/leaves#5: Adds the AppAdminAssignment model and AppUser navigation that this PR continues with schema, migration, and role-resolution work.

Suggested reviewers: sprucely, jSylvestre

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is too vague and reads like a branch name, so it doesn’t clearly describe the actual changes. Rename it to a concise, specific summary such as 'Add admin authorization and login flow'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch abc/auth-login

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (2)
client/src/routes/about.tsx (2)

8-9: 📐 Maintainability & Code Quality | 🔵 Trivial

Prefer TanStack Router's search-params handling over raw window.location.search.

This route doesn't define validateSearch, and reads query params directly via the DOM API instead of Route.useSearch(). As per coding guidelines, "route components should use TanStack Router hooks," which would also give typed, validated devLogin/returnUrl/error params.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/src/routes/about.tsx` around lines 8 - 9, The about route is reading
query params directly from window.location.search instead of using TanStack
Router search handling. Update the About route component to define and use
validateSearch on the route, then read devLogin, returnUrl, and error through
Route.useSearch() in the about route component rather than URLSearchParams. Keep
the logic in the About component aligned with the routed search params so they
are typed and validated by the router.

Source: Coding guidelines


8-21: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Dev login backdoor UI is reachable in production with no environment gate.

DevLoginPage renders purely based on the devLogin=1 query param, with no check like import.meta.env.DEV. Anyone can load /about?devLogin=1 in production and see the persona-switch UI (the actual persona sign-in is still blocked server-side by IsDevLoopback, but exposing this internal tooling and the Continue to {returnUrl} open-redirect surface, see below, in prod is unnecessary risk surface). As per coding guidelines, "Handle development versus production differences explicitly in environment-aware frontend code."

🛡️ Suggested gate
   const search = new URLSearchParams(window.location.search);
-  const isDevLogin = search.get('devLogin') === '1';
+  const isDevLogin = import.meta.env.DEV && search.get('devLogin') === '1';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/src/routes/about.tsx` around lines 8 - 21, The DevLoginPage branch in
about.tsx is controlled only by the devLogin query param, so add an explicit
environment gate before rendering it. Update the about route logic to require
import.meta.env.DEV (or equivalent production-safe check) alongside devLogin=1,
and keep the existing search/normalizeReturnUrl flow unchanged for dev only. Use
the about.tsx route component and the DevLoginPage conditional as the main
symbols to locate the fix.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@client/src/routes/`(authenticated)/admin.tsx:
- Around line 96-98: Extract the duplicated admin-role check into a shared
utility so both admin.tsx and AuthenticatedShell.tsx use the same canonical
implementation. Move the hasAdminRole logic (the user.roles.some lowercase
comparison) into a shared helper, then import and reuse it in the route guard
and shell/nav visibility code instead of redefining it locally.

In `@client/src/routes/about.tsx`:
- Around line 158-164: The client-side normalizeReturnUrl helper still allows
backslash-based open-redirect payloads, so update the validation in
normalizeReturnUrl to reject backslash variants as well as double-slash paths.
Mirror the same safety check used in the server-side NormalizeReturnUrl fix, and
ensure the Continue to... link in about.tsx only receives a strictly safe
relative path before rendering the <a href={returnUrl}> target.

In `@client/src/shared/auth/AuthenticatedShell.tsx`:
- Around line 13-17: The AuthenticatedShell props type is referencing
React.ReactNode without an explicit React import, which won’t resolve in this
module. Update AuthenticatedShell to import type ReactNode from react and change
the children prop annotation to use ReactNode directly, keeping the fix
localized to the AuthenticatedShell component definition.

In `@server/Controllers/AccountController.cs`:
- Around line 74-88: NormalizeReturnUrl in AccountController should reject
backslash-based open redirects instead of relying on the current prefix checks.
Update the returnUrl validation to use Url.IsLocalUrl so paths like /\evil.com
are treated as unsafe, and keep returning the fallbackPath for any non-local URL
before Redirect(safeReturnUrl) or RedirectUri uses it.

In `@server/Services/UserService.cs`:
- Around line 227-242: NormalizeAuthorizationKey currently accepts any Unicode
letter or digit via char.IsLetterOrDigit, which can produce values incompatible
with the non-Unicode IamId char(10) mapping used by AppUser and
AppAdminAssignment. Update NormalizeAuthorizationKey to restrict input to ASCII
alphanumerics only, then keep the existing trim, lowercase, and length checks so
the computed key matches what can be safely persisted.
- Around line 60-87: The first-login path in UserService is vulnerable to a race
where two concurrent calls both see no existing AppUser and then collide on the
unique EntraObjectId constraint when saving. Update the flow around
existingUser, ResolveAuthorizationKey, and the new AppUser creation so the
insert is idempotent: catch the unique-key conflict on SaveChangesAsync, requery
the AppUsers row by EntraObjectId, and reuse that record instead of failing.
Keep the logic in UserService consistent so only one user is created and the
rest of the fields are refreshed safely.
- Around line 213-226: The fallback IamId in the user key generation path is
being truncated too aggressively, which can create collisions and break
provisioning. Update the logic in the authorization-key helper used by
UserService to return a wider stable synthetic key based on entraObjectId
instead of slicing to 10 characters, and replace the unrelated Leaves/Walter
comment with a codebase-appropriate note about the temporary fallback strategy.
Ensure the change keeps the key deterministic and collision-resistant for
AppUser and AppAdminAssignment uniqueness.

---

Nitpick comments:
In `@client/src/routes/about.tsx`:
- Around line 8-9: The about route is reading query params directly from
window.location.search instead of using TanStack Router search handling. Update
the About route component to define and use validateSearch on the route, then
read devLogin, returnUrl, and error through Route.useSearch() in the about route
component rather than URLSearchParams. Keep the logic in the About component
aligned with the routed search params so they are typed and validated by the
router.
- Around line 8-21: The DevLoginPage branch in about.tsx is controlled only by
the devLogin query param, so add an explicit environment gate before rendering
it. Update the about route logic to require import.meta.env.DEV (or equivalent
production-safe check) alongside devLogin=1, and keep the existing
search/normalizeReturnUrl flow unchanged for dev only. Use the about.tsx route
component and the DevLoginPage conditional as the main symbols to locate the
fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9d53b2b5-fc0d-4c7d-aada-9f85eef644a1

📥 Commits

Reviewing files that changed from the base of the PR and between d962dc7 and 6d5c768.

📒 Files selected for processing (20)
  • client/src/queries/user.ts
  • client/src/routeTree.gen.ts
  • client/src/routes/(authenticated)/admin.tsx
  • client/src/routes/(authenticated)/route.tsx
  • client/src/routes/about.tsx
  • client/src/shared/auth/AuthenticatedShell.tsx
  • server.core/Data/AppDbContext.cs
  • server.core/Domain/AppAdminAssignment.cs
  • server.core/Domain/AppUser.cs
  • server.core/Migrations/20260702152625_AppAdminAssignment.Designer.cs
  • server.core/Migrations/20260702152625_AppAdminAssignment.cs
  • server.core/Migrations/AppDbContextModelSnapshot.cs
  • server/Controllers/AccountController.cs
  • server/Controllers/AdminController.cs
  • server/Controllers/UserController.cs
  • server/Helpers/AuthenticationHelper.cs
  • server/Helpers/ClaimsPrinciplesExtensions.cs
  • server/Program.cs
  • server/Services/UserService.cs
  • server/appsettings.json

Comment on lines +96 to +98
function hasAdminRole(user: User) {
return user.roles.some((role) => role.toLowerCase() === 'admin');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Extract hasAdminRole into a shared utility.

Identical logic (user.roles.some(role => role.toLowerCase() === 'admin')) is duplicated in AuthenticatedShell.tsx (Line 19). Since this gates both nav visibility and route access, keeping one canonical implementation avoids the two checks silently diverging later.

♻️ Proposed consolidation
+// client/src/queries/user.ts
+export function hasAdminRole(user: User): boolean {
+  return user.roles.some((role) => role.toLowerCase() === 'admin');
+}

Then import it in both admin.tsx and AuthenticatedShell.tsx instead of redefining locally.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/src/routes/`(authenticated)/admin.tsx around lines 96 - 98, Extract
the duplicated admin-role check into a shared utility so both admin.tsx and
AuthenticatedShell.tsx use the same canonical implementation. Move the
hasAdminRole logic (the user.roles.some lowercase comparison) into a shared
helper, then import and reuse it in the route guard and shell/nav visibility
code instead of redefining it locally.

Comment thread client/src/routes/about.tsx
Comment on lines +13 to +17
export const AuthenticatedShell = ({
children,
}: {
children: React.ReactNode;
}) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check tsconfig for allowUmdGlobalAccess, and whether this pattern is already used elsewhere
rg -n "allowUmdGlobalAccess" client/tsconfig.json client/tsconfig.app.json 2>/dev/null
rg -n "React\.ReactNode" client/src

Repository: ucdavis/leaves

Length of output: 351


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- tsconfig files ---\n'
git ls-files 'client/tsconfig*.json' || true

printf '\n--- allowUmdGlobalAccess occurrences ---\n'
rg -n "allowUmdGlobalAccess" client/tsconfig*.json client/package.json 2>/dev/null || true

printf '\n--- AuthenticatedShell and UserContext files ---\n'
sed -n '1,120p' client/src/shared/auth/AuthenticatedShell.tsx
printf '\n'
sed -n '1,120p' client/src/shared/auth/UserContext.tsx

Repository: ucdavis/leaves

Length of output: 243


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- tsconfig files ---'
git ls-files 'client/tsconfig*.json' || true

echo
echo '--- allowUmdGlobalAccess occurrences ---'
rg -n "allowUmdGlobalAccess" client/tsconfig*.json client/package.json 2>/dev/null || true

echo
echo '--- AuthenticatedShell ---'
sed -n '1,120p' client/src/shared/auth/AuthenticatedShell.tsx

echo
echo '--- UserContext ---'
sed -n '1,120p' client/src/shared/auth/UserContext.tsx

Repository: ucdavis/leaves

Length of output: 4066


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- client/tsconfig.json ---'
cat -n client/tsconfig.json

echo
echo '--- React type usage patterns in client/src/shared/auth ---'
rg -n "React\.ReactNode|ReactNode|import type .*react" client/src/shared/auth client/src 2>/dev/null || true

Repository: ucdavis/leaves

Length of output: 2352


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- client/tsconfig.json ---'
cat -n client/tsconfig.json

echo
echo '--- React type usage patterns in client/src/shared/auth ---'
rg -n "React\\.ReactNode|ReactNode|import type .*react" client/src/shared/auth client/src 2>/dev/null || true

Repository: ucdavis/leaves

Length of output: 2352


Import ReactNode explicitly here client/tsconfig.json doesn’t enable allowUmdGlobalAccess, so children: React.ReactNode won’t resolve in this module. Switch to import type { ReactNode } from 'react' and use children: ReactNode.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/src/shared/auth/AuthenticatedShell.tsx` around lines 13 - 17, The
AuthenticatedShell props type is referencing React.ReactNode without an explicit
React import, which won’t resolve in this module. Update AuthenticatedShell to
import type ReactNode from react and change the children prop annotation to use
ReactNode directly, keeping the fix localized to the AuthenticatedShell
component definition.

Comment thread server/Controllers/AccountController.cs Outdated
Comment thread server/Services/UserService.cs
Comment thread server/Services/UserService.cs
Comment on lines +227 to +242
private static string? NormalizeAuthorizationKey(string? value)
{
if (string.IsNullOrWhiteSpace(value))
{
return null;
}

var compact = new string(value.Where(char.IsLetterOrDigit).ToArray());
if (string.IsNullOrWhiteSpace(compact))
{
return null;
}

var normalized = compact.Trim().ToLowerInvariant();
return normalized.Length <= 10 ? normalized : null;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Non-ASCII characters allowed into a non-Unicode char(10) column.

char.IsLetterOrDigit accepts Unicode letters, but IamId is mapped as char(10) (non-Unicode) in both AppUser and AppAdminAssignment. Non-ASCII input (e.g., accented names) can be silently altered on write, causing the persisted key to differ from what was computed here.

🛠️ Restrict to ASCII alphanumerics
-        var compact = new string(value.Where(char.IsLetterOrDigit).ToArray());
+        var compact = new string(value.Where(char.IsAsciiLetterOrDigit).ToArray());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static string? NormalizeAuthorizationKey(string? value)
{
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
var compact = new string(value.Where(char.IsLetterOrDigit).ToArray());
if (string.IsNullOrWhiteSpace(compact))
{
return null;
}
var normalized = compact.Trim().ToLowerInvariant();
return normalized.Length <= 10 ? normalized : null;
}
private static string? NormalizeAuthorizationKey(string? value)
{
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
var compact = new string(value.Where(char.IsAsciiLetterOrDigit).ToArray());
if (string.IsNullOrWhiteSpace(compact))
{
return null;
}
var normalized = compact.Trim().ToLowerInvariant();
return normalized.Length <= 10 ? normalized : null;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/Services/UserService.cs` around lines 227 - 242,
NormalizeAuthorizationKey currently accepts any Unicode letter or digit via
char.IsLetterOrDigit, which can produce values incompatible with the non-Unicode
IamId char(10) mapping used by AppUser and AppAdminAssignment. Update
NormalizeAuthorizationKey to restrict input to ASCII alphanumerics only, then
keep the existing trim, lowercase, and length checks so the computed key matches
what can be safely persisted.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
server/Services/UserService.cs (2)

72-99: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Narrow existingUser before passing it to ApplyExistingUserUpdates.

The isNewUser boolean does not prove existingUser is non-null to nullable flow analysis, which matches the Validate warning at Line 94. Prefer branching directly on existingUser is null or assign a non-null local in the existing-user branch. As per coding guidelines, “Use C# with nullable reference types enabled.”

Proposed fix
-        var isNewUser = existingUser == null;
+        var isNewUser = existingUser is null;
         var shouldSaveUser = false;
-        if (isNewUser)
+        if (existingUser is null)
         {
             existingUser = new AppUser
             {
@@
         }
         else
         {
             shouldSaveUser = ApplyExistingUserUpdates(
                 existingUser,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/Services/UserService.cs` around lines 72 - 99, The `existingUser`
value is still nullable when passed into `ApplyExistingUserUpdates`, and the
`isNewUser` flag does not narrow it for nullable flow analysis. Update the
branching in `UserService` to check `existingUser is null` directly or assign
`existingUser` to a non-null local inside the existing-user path before calling
`ApplyExistingUserUpdates`, so the method receives a definitely non-null
`AppUser`.

Sources: Coding guidelines, Linters/SAST tools


65-69: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Don’t make the temporary IAM fallback permanent.

Line 65 reuses the stored IamId, and Lines 236-240 only set it when blank. A user first created with the temporary fallback on Lines 285-287 can never move to a later real iam_id/iamid, so admin assignments keyed to the real IAM ID may never apply. Consider tracking key source or allowing trusted direct IAM claims to replace synthetic fallback values.

Also applies to: 236-240, 285-287

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/Services/UserService.cs` around lines 65 - 69, The UserService IAM
resolution logic is treating the temporary fallback as permanent by always
preferring existingUser.IamId and only populating it when blank, which blocks
later replacement with a real IAM identifier. Update the resolution flow in
UserService, especially ResolveAuthorizationKey usage and the IamId persistence
path, so trusted direct IAM claims can overwrite synthetic fallback values or so
the source of the stored key is tracked before reusing it. Ensure the
create/update paths around the existing fallback logic distinguish temporary
values from real iam_id/iamid values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@server/Services/UserService.cs`:
- Around line 72-99: The `existingUser` value is still nullable when passed into
`ApplyExistingUserUpdates`, and the `isNewUser` flag does not narrow it for
nullable flow analysis. Update the branching in `UserService` to check
`existingUser is null` directly or assign `existingUser` to a non-null local
inside the existing-user path before calling `ApplyExistingUserUpdates`, so the
method receives a definitely non-null `AppUser`.
- Around line 65-69: The UserService IAM resolution logic is treating the
temporary fallback as permanent by always preferring existingUser.IamId and only
populating it when blank, which blocks later replacement with a real IAM
identifier. Update the resolution flow in UserService, especially
ResolveAuthorizationKey usage and the IamId persistence path, so trusted direct
IAM claims can overwrite synthetic fallback values or so the source of the
stored key is tracked before reusing it. Ensure the create/update paths around
the existing fallback logic distinguish temporary values from real iam_id/iamid
values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2148d5a9-28d6-4e94-b9ef-bbfb0b28cfb8

📥 Commits

Reviewing files that changed from the base of the PR and between 6d5c768 and 4fb9147.

📒 Files selected for processing (3)
  • client/src/routes/about.tsx
  • server/Controllers/AccountController.cs
  • server/Services/UserService.cs
🚧 Files skipped from review as they are similar to previous changes (2)
  • client/src/routes/about.tsx
  • server/Controllers/AccountController.cs

@jSylvestre jSylvestre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make a issue so we don't loose track of the IAM id flaw.
If people run this, they may need to delete their user record once it is fixed.

@aristachauhan
aristachauhan merged commit 47f6fb9 into main Jul 6, 2026
4 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 10, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants