Fix session persistence issue
- Created SSR-safe tokenStorage utility for localStorage access - Updated AuthContext with window availability checks - Enhanced API client interceptors with SSR safety - Improved error handling to only clear tokens on auth errors (401/403) - Added token refresh support for multiple response structures - Added redirect loop prevention in auth flow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
93
maternal-web/lib/utils/tokenStorage.ts
Normal file
93
maternal-web/lib/utils/tokenStorage.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Safe token storage utilities that work with both SSR and client-side rendering
|
||||
*/
|
||||
|
||||
export const tokenStorage = {
|
||||
/**
|
||||
* Get access token from storage
|
||||
*/
|
||||
getAccessToken: (): string | null => {
|
||||
if (typeof window === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return localStorage.getItem('accessToken');
|
||||
} catch (error) {
|
||||
console.error('Error reading accessToken:', error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get refresh token from storage
|
||||
*/
|
||||
getRefreshToken: (): string | null => {
|
||||
if (typeof window === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return localStorage.getItem('refreshToken');
|
||||
} catch (error) {
|
||||
console.error('Error reading refreshToken:', error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set access token in storage
|
||||
*/
|
||||
setAccessToken: (token: string): void => {
|
||||
if (typeof window === 'undefined') {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
localStorage.setItem('accessToken', token);
|
||||
} catch (error) {
|
||||
console.error('Error setting accessToken:', error);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set refresh token in storage
|
||||
*/
|
||||
setRefreshToken: (token: string): void => {
|
||||
if (typeof window === 'undefined') {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
localStorage.setItem('refreshToken', token);
|
||||
} catch (error) {
|
||||
console.error('Error setting refreshToken:', error);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set both tokens at once
|
||||
*/
|
||||
setTokens: (accessToken: string, refreshToken: string): void => {
|
||||
tokenStorage.setAccessToken(accessToken);
|
||||
tokenStorage.setRefreshToken(refreshToken);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear all tokens from storage
|
||||
*/
|
||||
clearTokens: (): void => {
|
||||
if (typeof window === 'undefined') {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
localStorage.removeItem('accessToken');
|
||||
localStorage.removeItem('refreshToken');
|
||||
} catch (error) {
|
||||
console.error('Error clearing tokens:', error);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if user has valid tokens
|
||||
*/
|
||||
hasTokens: (): boolean => {
|
||||
return !!(tokenStorage.getAccessToken() && tokenStorage.getRefreshToken());
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user