[feat]: 회원가입 페이지 개선 및 폼 자동 포맷팅 기능 추가
주요 변경사항: - 회원가입 폼에 사업자등록번호 자동 포맷팅 (000-00-00000) - 핸드폰 번호 자동 포맷팅 (010-1111-1111 / 010-111-1111) - 약관 전체 동의 체크박스 추가 및 개별 약관 연동 - 모든 입력 필드에 autocomplete 속성 추가 (브라우저 자동완성 지원) - 회원가입 API 연동 및 백엔드 통신 구현 - LoginPage 폼 태그 추가 및 DOM 경고 수정 - LanguageSelect 언어 변경 시 전체 페이지 새로고침으로 변경 - 다국어 번역 키 추가 (ko, en, ja) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
96
src/lib/auth/token-refresh.ts
Normal file
96
src/lib/auth/token-refresh.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Token Refresh Utility
|
||||
*
|
||||
* Handles automatic token refresh logic for client and server
|
||||
*/
|
||||
|
||||
/**
|
||||
* Client-side token refresh
|
||||
* Call this when you receive 401 errors from protected API calls
|
||||
*/
|
||||
export async function refreshTokenClient(): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch('/api/auth/refresh', {
|
||||
method: 'POST',
|
||||
credentials: 'include', // Include HttpOnly cookies
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const data = await response.json();
|
||||
|
||||
// If refresh failed and needs re-authentication
|
||||
if (data.needsReauth) {
|
||||
console.warn('🔄 Token refresh failed - redirecting to login');
|
||||
window.location.href = '/login';
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('✅ Token refreshed successfully');
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Token refresh error:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side token refresh (for API routes and middleware)
|
||||
*/
|
||||
export async function refreshTokenServer(refreshToken: string): Promise<{
|
||||
success: boolean;
|
||||
accessToken?: string;
|
||||
newRefreshToken?: string;
|
||||
expiresIn?: number;
|
||||
}> {
|
||||
try {
|
||||
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/v1/refresh`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'Authorization': `Bearer ${refreshToken}`,
|
||||
'X-API-KEY': process.env.NEXT_PUBLIC_API_KEY || '',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return { success: false };
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
accessToken: data.access_token,
|
||||
newRefreshToken: data.refresh_token,
|
||||
expiresIn: data.expires_in,
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('Token refresh error:', error);
|
||||
return { success: false };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if token is expired or about to expire (within 5 minutes)
|
||||
* @param expiresAt - Expiration timestamp from backend (e.g., "2025-11-10 15:49:38")
|
||||
*/
|
||||
export function shouldRefreshToken(expiresAt: string | null): boolean {
|
||||
if (!expiresAt) return true; // If no expiration info, assume expired
|
||||
|
||||
try {
|
||||
const expiryTime = new Date(expiresAt).getTime();
|
||||
const currentTime = Date.now();
|
||||
const fiveMinutes = 5 * 60 * 1000; // 5 minutes in milliseconds
|
||||
|
||||
// Refresh if token expires in less than 5 minutes
|
||||
return (expiryTime - currentTime) < fiveMinutes;
|
||||
} catch {
|
||||
return true; // If parsing fails, assume expired
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user