Fix frequent re-login issue caused by stale JWT tokens
Problem: Users experiencing frequent forced re-logins after backend restarts, especially with 8-hour token expiration in production. Root cause analysis: 1. JWT tokens stored in localStorage on browser 2. Backend restarts with potentially different JWT secret key 3. Frontend doesn't validate stored token on app startup 4. User navigates normally, then first API request returns 401 5. User surprised with sudden logout This fix adds token validation on app startup. If a stored token exists, immediately verify it with /api/auth/me before mounting the app. If the token is invalid (expired or stale secret), user is logged out at startup rather than mid-session. Additional issue found (not committed - .env files in .gitignore): - .env and .env.docker had DIFFERENT JWT_SECRET_KEY values - Fixed locally: standardized to same key across all .env files - Action required: Verify production JWT_SECRET_KEY is consistent and persisted Changes: - frontend/src/main.js: Call authStore.fetchUser() on app load if token exists - Logout happens immediately at page load, not on first interaction - Better UX: "please log in" vs "surprise logout while working" Future improvement (not in this commit): - Implement automatic token refresh before expiration - Add proactive refresh timer (e.g., every 7 hours for 8-hour tokens) - Would eliminate re-login entirely for active sessions Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,12 +9,24 @@ import '@fontsource-variable/inter'
|
||||
// Initialize theme on app load
|
||||
import './stores/theme'
|
||||
import { applyBranding } from './utils/siteSettings'
|
||||
import { useAuthStore } from './stores/auth'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
|
||||
// Validate stored token on app startup. If a token exists in localStorage but
|
||||
// is expired or signed with a stale secret (backend restarted), this catches
|
||||
// it immediately rather than letting the user navigate and then get kicked on
|
||||
// the first API request. fetchUser() logs out on 401.
|
||||
const authStore = useAuthStore()
|
||||
if (authStore.isAuthenticated) {
|
||||
authStore.fetchUser().catch(() => {
|
||||
// fetchUser handles the logout on 401; ignore the promise rejection
|
||||
})
|
||||
}
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
// Apply per-site favicon + brand color once settings load (no-op on defaults).
|
||||
|
||||
Reference in New Issue
Block a user