fix: align frontend auth with httpOnly cookie strategy#159
Merged
Conversation
The backend switched to httpOnly cookie auth in bc64610 but the frontend was never updated — login stored data.access_token (undefined) in localStorage, causing every request to send Authorization: Bearer undefined and get a 401. - Remove all localStorage token reads/writes from Login, Register, Dashboard, Profile, and Inventory pages - Add credentials: 'include' to all fetch calls - Add withCredentials: true to all axios calls in service files - Replace ProtectedRoute localStorage check with GET /auth/me so auth state is verified via cookie (httpOnly cookies are unreadable from JS) - Call POST /auth/logout on logout to revoke the refresh token and blacklist the JTI in Redis
Contributor
There was a problem hiding this comment.
Pull request overview
Aligns the frontend with the backend's already-deployed httpOnly cookie auth scheme. Previously the frontend was reading data.access_token from a login response that no longer carries it, then sending Authorization: Bearer undefined on every call — breaking all authenticated flows.
Changes:
- Removes all
localStoragetoken reads/writes from auth/login/register/profile/dashboard/inventory pages and from five service files; the shared axios instance and every per-call axios/fetch invocation now sendswithCredentials: true/credentials: 'include'so cookies travel with cross-origin requests. - Replaces
ProtectedRoute's localStorage check with a realGET /auth/mecall (httpOnly cookies aren't readable from JS). - Adds a
POST /auth/logoutcall on logout inProfile,Dashboard, andInventoryso the backend can revoke the refresh token and blacklist the JTI.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/services/uex.service.ts | Drops bearer header helper; switches both UEX GETs to withCredentials. |
| frontend/src/services/permissions.service.ts | Drops bearer header helper; uses withCredentials on the user-permissions GET. |
| frontend/src/services/location.service.ts | Drops bearer header; locations + storable-locations now send credentials, preserving If-None-Match. |
| frontend/src/services/inventory.service.ts | Drops bearer header helper across all inventory and org-inventory CRUD calls in favor of withCredentials. |
| frontend/src/services/api.service.ts | Marks the shared axios instance with withCredentials; getProfile no longer takes a token. |
| frontend/src/pages/Register.tsx | Adds credentials: 'include' to register/auto-login fetches and stops storing tokens locally. |
| frontend/src/pages/Profile.tsx | Profile read/update and password-change fetches use cookies; logout calls POST /auth/logout. |
| frontend/src/pages/Login.tsx | Adds credentials: 'include'; no longer parses/stores tokens from the login response. |
| frontend/src/pages/Inventory.tsx | Profile fetch uses cookies; logout now hits the server logout endpoint. |
| frontend/src/pages/Dashboard.tsx | Profile fetch uses cookies; logout now hits the server logout endpoint. |
| frontend/src/components/ProtectedRoute.tsx | Replaces synchronous localStorage check with an async GET /auth/me round-trip and authed state. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Wrap all three handleLogout fetch calls in try/finally so navigate('/login')
always runs regardless of network errors or 401 from RefreshTokenAuthGuard
- ProtectedRoute: show CircularProgress spinner while auth check is in flight
instead of rendering null; only redirect to /login on explicit 401 — network
errors and 5xx leave the spinner up to avoid booting users on transient failures
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.
Closes #158
Summary
data.access_tokenwasundefinedat login, so every request sentAuthorization: Bearer undefinedand got a 401credentials: 'include'(fetch) andwithCredentials: true(axios) everywhere so cookies are sent automatically on cross-origin requestsProtectedRoutelocalStorage check with a realGET /auth/mecall — httpOnly cookies are intentionally unreadable from JSPOST /auth/logoutto revoke the refresh token and blacklist the JTI in Redis (previously just cleared localStorage with no server-side effect)Test plan
demo/password123— should land on dashboard without 401s in the network tab/loginand a subsequent visit to/dashboardshould redirect back to/loginaccess_tokenorrefresh_tokenkeys should existaccess_tokenandrefresh_tokenshould be present withHttpOnlyflag set