Issue ID: [Auth] Fix Token Key Mismatch Between Storage and Retrieval
Status:
Date: March 25, 2026
Severity: High - Breaks notification system authentication
The frontend has an inconsistency in how authentication tokens are stored and retrieved from localStorage, causing the notification system to fail authentication for logged-in users.
-
Token Storage (Login.tsx):
- Uses
tokenStorage.setAccessToken(res.accessToken) - Stores token under key:
'stellarcert_access_token'(defined in api/tokens.ts)
- Uses
-
Token Retrieval (Multiple files):
- Uses
localStorage.getItem('token') - Attempts to retrieve token under key:
'token'(incorrect) - Result: Always gets
null, fails authentication
- Uses
- Line 37:
const token = localStorage.getItem('token');infetchNotifications() - Line 54:
const token = localStorage.getItem('token');inuseEffect() - Line 74:
const token = localStorage.getItem('token');inmarkAsRead() - Line 89:
const token = localStorage.getItem('token');inmarkAllAsRead()
Impact: Notification system cannot authenticate API requests to:
- Fetch notifications endpoint
- Subscribe to WebSocket connection
- Mark notifications as read
- Mark all notifications as read
- Line 53:
const token = localStorage.getItem('token');inhandleSave()
Impact: Users cannot save notification preferences
const ACCESS_TOKEN_KEY = 'stellarcert_access_token';
const REFRESH_TOKEN_KEY = 'stellarcert_refresh_token';
export const tokenStorage = {
getAccessToken: (): string | null => {
return localStorage.getItem(ACCESS_TOKEN_KEY);
},
setAccessToken: (token: string): void => {
localStorage.setItem(ACCESS_TOKEN_KEY, token);
},
// ... other methods
};Key Insight: A centralized tokenStorage utility already exists and should be used consistently across the application.
The context is using raw localStorage.getItem('token') calls instead of the standardized tokenStorage utility:
// ❌ Current (Broken)
const token = localStorage.getItem('token');
// ✅ Should be
const token = tokenStorage.getAccessToken();Similar inconsistency:
// ❌ Current (Broken)
const token = localStorage.getItem('token');
// ✅ Should be
const token = tokenStorage.getAccessToken();Use the standardized tokenStorage utility across all files instead of directly accessing localStorage with inconsistent keys.
- Import
tokenStoragefrom../api/tokens - Replace all 4 instances of
localStorage.getItem('token')withtokenStorage.getAccessToken() - Files affected:
- Line 37 → fetchNotifications()
- Line 54 → useEffect()
- Line 74 → markAsRead()
- Line 89 → markAllAsRead()
- Import
tokenStoragefrom../api/tokens - Replace line 53:
localStorage.getItem('token')withtokenStorage.getAccessToken() - File affected:
- Line 53 → handleSave()
- Add import statement to NotificationContext.tsx:
import { tokenStorage } from '../api/tokens'; - Replace 4 instances in NotificationContext.tsx
- Add import statement to NotificationPreferences.tsx:
import { tokenStorage } from '../api/tokens'; - Replace 1 instance in NotificationPreferences.tsx
- Test notification system:
- Login to application
- Verify notifications load correctly
- Verify WebSocket connection establishes
- Test marking notifications as read
- Test marking all as read
- Test saving notification preferences
- Verify no console errors related to authentication
- ✅ Upon successful login, accessToken is stored under
'stellarcert_access_token' - ✅ NotificationContext correctly retrieves the token using the same key
- ✅ API requests to notification endpoints include valid Bearer token
- ✅ WebSocket connection auth succeeds
- ✅ Notification system functions for authenticated users
Using the centralized tokenStorage utility provides:
- Single source of truth: Token keys defined in one place
- Consistency: All token access goes through the same interface
- Maintainability: Future changes to token storage only need updates in one file
- Type safety: Methods have proper TypeScript typing (returns
string | null) - Encapsulation: Abstraction layer between storage mechanism and code
Other components that correctly use tokenStorage (for reference):
- Login.tsx: Uses
tokenStorage.setAccessToken()✅ - App.tsx or other API call handlers may also need review
Check for other direct localStorage access patterns:
localStorage.getItem('token')localStorage.getItem('refreshToken')localStorage.getItem('accessToken')
All should be routed through the tokenStorage utility for consistency.
- Token Utility: api/tokens.ts
- NotificationContext: context/NotificationContext.tsx
- NotificationPreferences: pages/NotificationPreferences.tsx
- Login Page: pages/Login.tsx