Summary
The TourEase App.jsx documentation explicitly states that the JWT auth token is stored in localStorage and validated by a ProtectedRoute component on every navigation. Storing JWTs in localStorage is a well-documented security vulnerability: any JavaScript running on the page — including third-party scripts, CDN-injected code, or a successful XSS injection — can read the token directly, impersonate the user, and make authenticated API calls without any session expiry constraint.
Problem
From the project architecture documentation:
Auth token → localStorage → ProtectedRoute in App.jsx
localStorage is accessible to any JavaScript running in the same origin, making it trivially exfiltrable via XSS.
TourEase integrates OpenAI, Google OAuth, and external weather/event APIs — any one of these integration points, if misconfigured, could introduce a script that reads the stored token.
There is no mention of token rotation, refresh token logic, or short-lived token enforcement.
Impact
A successful XSS attack on any TourEase page gives the attacker the full JWT, which can then be used to make authenticated requests (/api/trip, /api/itinerary) from any origin until the token naturally expires.
Users who believe they have "logged out" may still have their token exposed in browser storage if the logout only clears localStorage client-side without server-side invalidation.
Proposed Solution
I would like to implement a more secure authentication strategy using HttpOnly cookies:
Backend change — Set the JWT as an HttpOnly, Secure, SameSite=Strict cookie in the /api/auth/login and /api/auth/google/callback responses instead of returning it in the JSON body.
js
// In auth controller (login success)
res.cookie('token', jwt, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
});
res.json({ success: true, user: { name, email } });
Frontend change — Remove the localStorage.getItem('token') pattern in ProtectedRoute. Instead, rely on the cookie being sent automatically with every credentials: 'include' Axios request. A /api/auth/me endpoint returns the current user or 401.
Logout — Call /api/auth/logout which clears the cookie server-side (res.clearCookie('token')), making logout cryptographically reliable.
CSRF protection — Since we are switching to cookies, I will add a CSRF token header check (double-submit cookie pattern) on state-mutating endpoints.
This is a targeted, backwards-compatible change. I will open it as a focused PR with before/after documentation.
Could you assign this issue to me?
Labels: security, bug, enhancement, GSSoC 2026
Summary
The TourEase App.jsx documentation explicitly states that the JWT auth token is stored in localStorage and validated by a ProtectedRoute component on every navigation. Storing JWTs in localStorage is a well-documented security vulnerability: any JavaScript running on the page — including third-party scripts, CDN-injected code, or a successful XSS injection — can read the token directly, impersonate the user, and make authenticated API calls without any session expiry constraint.
Problem
From the project architecture documentation:
Auth token → localStorage → ProtectedRoute in App.jsx
localStorage is accessible to any JavaScript running in the same origin, making it trivially exfiltrable via XSS.
TourEase integrates OpenAI, Google OAuth, and external weather/event APIs — any one of these integration points, if misconfigured, could introduce a script that reads the stored token.
There is no mention of token rotation, refresh token logic, or short-lived token enforcement.
Impact
A successful XSS attack on any TourEase page gives the attacker the full JWT, which can then be used to make authenticated requests (/api/trip, /api/itinerary) from any origin until the token naturally expires.
Users who believe they have "logged out" may still have their token exposed in browser storage if the logout only clears localStorage client-side without server-side invalidation.
Proposed Solution
I would like to implement a more secure authentication strategy using HttpOnly cookies:
Backend change — Set the JWT as an HttpOnly, Secure, SameSite=Strict cookie in the /api/auth/login and /api/auth/google/callback responses instead of returning it in the JSON body.
js
// In auth controller (login success)
res.cookie('token', jwt, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
});
res.json({ success: true, user: { name, email } });
Frontend change — Remove the localStorage.getItem('token') pattern in ProtectedRoute. Instead, rely on the cookie being sent automatically with every credentials: 'include' Axios request. A /api/auth/me endpoint returns the current user or 401.
Logout — Call /api/auth/logout which clears the cookie server-side (res.clearCookie('token')), making logout cryptographically reliable.
CSRF protection — Since we are switching to cookies, I will add a CSRF token header check (double-submit cookie pattern) on state-mutating endpoints.
This is a targeted, backwards-compatible change. I will open it as a focused PR with before/after documentation.
Could you assign this issue to me?
Labels: security, bug, enhancement, GSSoC 2026