Skip to content

feat(frontend): add reusable useUser hook and header auth UX#943

Merged
northdpole merged 3 commits into
OWASP:mainfrom
skypank-coder:feat/frontend-useuser-header-auth
Jul 8, 2026
Merged

feat(frontend): add reusable useUser hook and header auth UX#943
northdpole merged 3 commits into
OWASP:mainfrom
skypank-coder:feat/frontend-useuser-header-auth

Conversation

@skypank-coder

Copy link
Copy Markdown
Contributor

Scoped to non-MyOpenCRE auth UX per @Pa04rth 's steer (b): a reusable useUser hook + header login/user/logout state, following the existing chatbot auth pattern. Part of the Login MVP (@northdpole 's priority #1).

useUser probes /rest/v1/user and treats 401 as anonymous — no forced redirect, so public pages stay open to anonymous users (consistent with the public-reads-stay-open / v2 direction @ outlined).
Header shows the logged-in user + Logout, or a Login button when anonymous.
Frontend-only. No backend changes. No myopencre/capabilities coupling (left to Prateek).

Verified manually in dev: NO_LOGIN=1 shows logged-in state; unauthenticated shows Login with no redirect on load; login/logout flows work.
Closes #942 .

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 2cc079f5-fa77-4419-a7c0-b0a2c3c7ff9c

📥 Commits

Reviewing files that changed from the base of the PR and between f960dbd and 13b473a.

📒 Files selected for processing (3)
  • application/frontend/src/hooks/index.ts
  • application/frontend/src/hooks/useUser.ts
  • application/frontend/src/scaffolding/Header/Header.tsx
✅ Files skipped from review due to trivial changes (1)
  • application/frontend/src/hooks/index.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • application/frontend/src/scaffolding/Header/Header.tsx
  • application/frontend/src/hooks/useUser.ts

Summary by CodeRabbit

  • New Features
    • Added account-aware header controls that show the signed-in user when available.
    • Added login and logout actions in both desktop and mobile views.
    • Introduced a user session hook that tracks sign-in status and loading state.
  • Bug Fixes
    • Improved handling for unauthenticated and empty user responses so the interface falls back gracefully.

Walkthrough

Introduces a useUser hook that fetches authentication state from /user, handling logged-in, anonymous (401), and error cases, and exposes login/logout redirect actions. The Header component is updated to conditionally render login/logout UI on desktop and mobile based on this state.

Changes

User Auth State and Header Integration

Layer / File(s) Summary
useUser hook and public export
application/frontend/src/hooks/useUser.ts, application/frontend/src/hooks/index.ts
Adds UserState type and useUser hook that fetches /user, resolves login state from HTTP status (200/401/other), guards against post-unmount updates, and exposes login/logout redirects; re-exported from the hooks barrel.
Header auth UI with conditional login/logout
application/frontend/src/scaffolding/Header/Header.tsx
Header imports useUser and LogOut/User icons, destructures auth state, and replaces desktop and mobile auth markup with conditional login/logout rendering gated on capabilities.login && !userLoading.

Estimated code review effort: 2 (Simple) | ~12 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The hook and header UX match #942, but the header still appears to depend on capabilities.login, which the issue marked out of scope. Remove capabilities.login gating from this PR and keep it focused on the shared useUser hook plus header login/logout UI.
Out of Scope Changes check ⚠️ Warning Header auth rendering appears to introduce or retain capabilities.login coupling, which was explicitly out of scope for this PR. Drop the capabilities.login dependency from the header auth changes and leave capabilities work to the separate effort.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main frontend auth change by mentioning the reusable useUser hook and header auth UX.
Description check ✅ Passed The description matches the PR by describing the new user hook, header login/logout behavior, and frontend-only scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

application/frontend/src/hooks/index.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

application/frontend/src/hooks/useUser.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

application/frontend/src/scaffolding/Header/Header.tsx

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.


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
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
application/frontend/src/hooks/useUser.ts (1)

16-39: Use async/await instead of Promise chaining in this new TS hook.

This new frontend TypeScript code uses raw .then/.catch/.finally; please rewrite to async/await for consistency with project standards.
As per coding guidelines, "Prefer async/await over raw Promise chains or callbacks in new TypeScript frontend code."

Suggested refactor
-  useEffect(() => {
-    let active = true;
-    fetch(`${apiUrl}/user`, { method: 'GET' })
-      .then((res) => {
-        if (res.status === 200) {
-          return res.text();
-        }
-        return null; // 401 or anything else => treated as not logged in
-      })
-      .then((value) => {
-        if (active) {
-          setUser(value && value.trim() !== '' ? value : null);
-        }
-      })
-      .catch(() => {
-        if (active) {
-          setUser(null); // network error => treat as anonymous, do NOT redirect
-        }
-      })
-      .finally(() => {
-        if (active) {
-          setLoading(false);
-        }
-      });
-    return () => {
-      active = false;
-    };
-  }, [apiUrl]);
+  useEffect(() => {
+    let active = true;
+    const loadUser = async () => {
+      try {
+        const res = await fetch(`${apiUrl}/user`, { method: 'GET' });
+        if (res.status === 200) {
+          const value = await res.text();
+          if (active) setUser(value.trim() !== '' ? value : null);
+          return;
+        }
+        if (active) setUser(null);
+      } catch {
+        if (active) setUser(null);
+      } finally {
+        if (active) setLoading(false);
+      }
+    };
+    void loadUser();
+    return () => {
+      active = false;
+    };
+  }, [apiUrl]);
🤖 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 `@application/frontend/src/hooks/useUser.ts` around lines 16 - 39, The
useEffect hook in the useUser function uses Promise chaining with
.then/.catch/.finally methods, which should be converted to async/await syntax
for consistency with project standards. Create an async function inside the
useEffect that performs the fetch call to the user endpoint, use try/catch
blocks instead of .catch(), and replace the .then() chaining with await
statements. Ensure the active flag check is maintained at each operation (after
fetch, after setting user state, and in the cleanup) to prevent state updates on
unmounted components, and keep the setLoading(false) call in a finally block or
after the try/catch completes.

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 `@application/frontend/src/hooks/useUser.ts`:
- Around line 20-24: In the useUser hook, the current logic treats all non-200
HTTP responses as anonymous by returning null. Instead of collapsing all non-200
responses together, you should differentiate between them: return res.text() for
status 200, return null specifically for status 401 (unauthorized/anonymous),
and for all other status codes (like 5xx errors), throw an error or handle them
as actual failures rather than masking them as normal logged-out state. Apply
this same correction to both occurrences mentioned in the diff (lines 20-24 and
lines 30-33).

---

Nitpick comments:
In `@application/frontend/src/hooks/useUser.ts`:
- Around line 16-39: The useEffect hook in the useUser function uses Promise
chaining with .then/.catch/.finally methods, which should be converted to
async/await syntax for consistency with project standards. Create an async
function inside the useEffect that performs the fetch call to the user endpoint,
use try/catch blocks instead of .catch(), and replace the .then() chaining with
await statements. Ensure the active flag check is maintained at each operation
(after fetch, after setting user state, and in the cleanup) to prevent state
updates on unmounted components, and keep the setLoading(false) call in a
finally block or after the try/catch completes.
🪄 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: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 8e57915e-65e6-459b-95f0-ef4cd0130eb7

📥 Commits

Reviewing files that changed from the base of the PR and between 13d2f04 and 4c0d5bc.

📒 Files selected for processing (3)
  • application/frontend/src/hooks/index.ts
  • application/frontend/src/hooks/useUser.ts
  • application/frontend/src/scaffolding/Header/Header.tsx

Comment thread application/frontend/src/hooks/useUser.ts

@northdpole northdpole left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Direction looks good — useUser treating 401 as anonymous (no redirect) is what we want.

One ask before merge: gate the header Login/Logout behind capabilities.login, same pattern as capabilities.myopencre. We want to roll out auth UI per-environment; prod should be able to hide it with login: false until we're ready.

useUser can stay as-is — just wrap the header auth blocks in capabilities.login && …. Default login: false when /api/capabilities is missing/fails is fine for now.

Capabilities endpoint wiring can be a small follow-up if you prefer, but please don't merge always-on header auth without the gate.

@skypank-coder

Copy link
Copy Markdown
Contributor Author

@northdpole Pushed updates addressing both review comments .

@skypank-coder skypank-coder requested a review from northdpole June 23, 2026 11:15
northdpole added a commit to skypank-coder/OpenCRE that referenced this pull request Jul 8, 2026
Expose login alongside myopencre on GET /api/capabilities so auth UI
(OWASP#943) can roll out behind an env flag; defaults remain off on prod.

Co-authored-by: Cursor <cursoragent@cursor.com>
northdpole added a commit that referenced this pull request Jul 8, 2026
Expose login alongside myopencre on GET /api/capabilities so auth UI
(#943) can roll out behind an env flag; defaults remain off on prod.

Co-authored-by: Cursor <cursoragent@cursor.com>
@northdpole northdpole force-pushed the feat/frontend-useuser-header-auth branch from c067497 to 13b473a Compare July 8, 2026 09:56

@northdpole northdpole left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Rebased onto main after #949. Kept main's useCapabilities normalization; Header auth UI gated on capabilities.login as requested. useUser treats 401 as anonymous with no redirect — good for public-read pages.

@northdpole northdpole merged commit ed68edf into OWASP:main Jul 8, 2026
6 checks passed
@northdpole

Copy link
Copy Markdown
Collaborator

Thanks @skypank-coder — clean work on the Login MVP. The useUser hook (401 → anonymous, no redirect) and gating Header auth behind capabilities.login are exactly what we wanted for a safe per-environment rollout. Appreciate the quick follow-ups on review feedback too.

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.

Login MVP: add reusable user/auth state + header login/logout UX

2 participants