Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/api/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,18 @@ baseAPI.interceptors.response.use(
const isServer = typeof window === 'undefined';
const originalRequest = error.config;

// skipAuthRedirect flag가 지정되어있지 않으면 항상 redirect 되도록
if (originalRequest.skipAuthRedirect === undefined) {
originalRequest.skipAuthRedirect = true;
}

if (status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
await API.authService.refresh(originalRequest.skipAuthRedirect);
// refresh - set cookie는 클라이언트 요청만 동작함
if (!isServer) {
await API.authService.refresh(originalRequest.skipAuthRedirect);
}
return baseAPI(originalRequest);
} catch (refreshError) {
if (!originalRequest.skipAuthRedirect) throw refreshError;
Expand Down
5 changes: 4 additions & 1 deletion src/app/(user)/profile/[userId]/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { formatISO } from '@/lib/formatDateTime';
import { server } from '@/mock/server';
import { createMockSuccessResponse } from '@/mock/service/common/common-mock';
import { mockUserItems } from '@/mock/service/user/user-mock';
import { AuthProvider } from '@/providers';

import ProfilePage from './page';

Expand Down Expand Up @@ -33,7 +34,9 @@ const renderWithQueryClient = async (component: React.ReactElement) => {
let renderResult;
await act(async () => {
renderResult = render(
<QueryClientProvider client={testQueryClient}>{component}</QueryClientProvider>,
<QueryClientProvider client={testQueryClient}>
<AuthProvider hasRefreshToken={false}>{component}</AuthProvider>
</QueryClientProvider>,
);
});

Expand Down
8 changes: 6 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,19 @@ export const metadata: Metadata = {

initMocks();

export default function RootLayout({
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const { cookies } = await import('next/headers');
const cookieStore = await cookies();
const hasRefreshToken = !!cookieStore.get('refreshToken')?.value;

return (
<html lang='ko'>
<body className={`${pretendard.className} ${pretendard.variable} antialiased`}>
<Providers>
<Providers hasRefreshToken={hasRefreshToken}>
<div id='root'>
<LayoutWrapper>{children}</LayoutWrapper>
</div>
Expand Down
5 changes: 3 additions & 2 deletions src/app/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import {

interface Props {
children: React.ReactNode;
hasRefreshToken: boolean;
}

export const Providers = ({ children }: Props) => {
export const Providers = ({ children, hasRefreshToken }: Props) => {
return (
<QueryProvider>
<MSWProvider>
<AuthProvider>
<AuthProvider hasRefreshToken={hasRefreshToken}>
<NotificationProvider>
<LazyMotionProvider>
<ToastProvider>
Expand Down
5 changes: 5 additions & 0 deletions src/hooks/use-user/use-user-get-me/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useQuery } from '@tanstack/react-query';

import { API } from '@/api';
import { userKeys } from '@/lib/query-key/query-key-user';
import { useAuth } from '@/providers';

export const useUserGetMe = () => {
const query = useQuery({
Expand All @@ -18,6 +19,8 @@ export const useUserGetMe = () => {
};

export const useUserGetMeSkipRedirect = () => {
const { isAuthenticated } = useAuth();

const query = useQuery({
queryKey: userKeys.me(),
queryFn: () => API.userService.getMeSkipRedirect(),
Expand All @@ -27,6 +30,8 @@ export const useUserGetMeSkipRedirect = () => {
profileMessage: data.profileMessage ?? '',
mbti: data.mbti ?? '',
}),
retry: false,
enabled: isAuthenticated,
});
return query;
};
11 changes: 6 additions & 5 deletions src/providers/provider-auth/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,30 @@ export const useAuth = () => {

interface Props {
children: React.ReactNode;
hasRefreshToken: boolean;
}

export const AuthProvider = ({ children }: Props) => {
export const AuthProvider = ({ children, hasRefreshToken }: Props) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);

// 초기값 설정
// 페이지가 새로고침 될 때 accessToken이 없으면 refresh 시도, state update 실행
useEffect(() => {
const updateAuthenticated = async () => {
const accessToken = Cookies.get('accessToken');
if (!accessToken) {
const hasAccessToken = !!Cookies.get('accessToken');
if (!hasAccessToken && hasRefreshToken) {
try {
await API.authService.refresh();
setIsAuthenticated(true);
} catch {
setIsAuthenticated(false);
}
} else {
} else if (hasAccessToken) {
setIsAuthenticated(true);
}
};
updateAuthenticated();
}, []);
}, [hasRefreshToken]);

return (
<AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated }}>
Expand Down