'use client'; import React, { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { API_URL } from './config'; import { withSessionRequest } from './csrf'; interface AuthUser { userId: number; username: string; role: string; } interface AuthContextValue { user: AuthUser | null; loading: boolean; login: (username: string, password: string) => Promise; logout: () => void; isAuthenticated: boolean; } const AuthContext = createContext({ user: null, loading: true, login: async () => {}, logout: () => {}, isAuthenticated: false, }); export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const loadUser = useCallback(async () => { try { const res = await fetch(`${API_URL}/api/auth/me`, withSessionRequest()); if (res.ok) { const data = await res.json(); setUser({ userId: data.id, username: data.username, role: data.role }); } else if (res.status === 401) { // access token expired → try refresh via cookie try { const rRes = await fetch(`${API_URL}/api/auth/refresh`, withSessionRequest({ method: 'POST' }, { csrf: true })); if (rRes.ok) { const d = await rRes.json(); setUser({ userId: 0, username: d.username, role: d.role }); } } catch { /* silent */ } } } catch { // silent } finally { setLoading(false); } }, []); useEffect(() => { loadUser(); }, [loadUser]); const login = async (username: string, password: string) => { const res = await fetch(`${API_URL}/api/auth/login`, withSessionRequest({ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }), }, { csrf: true })); if (!res.ok) { const d = await res.json(); throw new Error(d.message ?? '로그인 실패'); } const d = await res.json(); // Tokens are set as HttpOnly cookies by the server setUser({ userId: 0, username: d.username, role: d.role }); // Fetch actual userId from /me try { const meRes = await fetch(`${API_URL}/api/auth/me`, withSessionRequest()); if (meRes.ok) { const me = await meRes.json(); setUser({ userId: me.id, username: me.username, role: me.role }); } } catch { /* fallback — already set basic info */ } }; const logout = async () => { try { await fetch(`${API_URL}/api/auth/logout`, withSessionRequest({ method: 'POST' }, { csrf: true })); } catch { /* silent */ } setUser(null); }; return ( {children} ); } export function useAuth() { return useContext(AuthContext); }