ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Bug Fix] Next.js 14 App Router 버전 OAuth Session 동기화 문제
    Front-end 개발/FE 버그 2024. 11. 17. 10:34

     

    Next.js 14 App Router 버전으로 개발을 진행하면서 Header 컴포넌트에 로그인/로그아웃 기능을 넣고 email 로그인을 해봤는데 로그인 상태가 변경되지 않는 이슈가 발생했다.

    1. Problem


    [ 문제 정의 ]

    Email 로그인 (signInWithCredentials) 할 경우 세션 값이 새로고침 해야 업데이트 되는 문제

    [ 원인 분석 ]

    useSession Hook의 경우 loading, unauthenticated, authenticated로 3 가지 Status로 구분된다. 현재 로그인 후 accessToken이 잘 들어옴에도 loading → unauthenticated 상태에 그치고, 새로고침을 해야 loading → authenticated 상태로 변경되는 상황이다.

    [ 문제 접근 ] 

    이 문제는 세션 정보가 클라이언트 컴포넌트에서 즉시 업데이트 되지 않기 때문에 발생한 것으로 판단된다.  Next 서버에서 OAuth를 통해 로그인을 처리 한 후에 서버 액션으로 클라이언트(브라우저)를 redirect 이후 클라이언트 컴포넌트가 세션 정보를 즉시 가져오지 못하는 상태인 것으로 확인된다. 즉, 서버와 클라이언트의 세션 정보 동기화 문제로 파악.

    2. Solution


    커스텀 훅을 만들어서 pathname이 바뀔 때 마다 세션 정보를 갱신하는 반응형 세션을 적용하여 해결함.

    추가적으로 세션의 상태를 확인할 수 있는 status를 파악할 수 있도록 커스텀 세션 훅에 기능 추가.

     

    // hook/useSession.tsx
    'use client';
    
    import { Session } from 'next-auth';
    import { getSession } from 'next-auth/react';
    import { usePathname } from 'next/navigation';
    import { createContext, useContext, useEffect, useState } from 'react';
    
    interface UseSessionResult {
      session: Session | null;
      status: 'loading' | 'authenticated' | 'unauthenticated';
    }
    
    const SessionContent = createContext<UseSessionResult>({ session: null, status: 'loading' });
    
    export const SessionProvider = ({ children }: { children: React.ReactNode }) => {
      const pathname = usePathname();
      const [session, setSession] = useState<Session | null>(null);
      const [status, setStatus] = useState<'loading' | 'authenticated' | 'unauthenticated'>('loading');
      useEffect(() => {
        setStatus('loading');
        getSession().then((res) => {
          setSession(res);
          setStatus(res ? 'authenticated' : 'unauthenticated');
        });
      }, [pathname]); // 페이지를 이동할 때마다 세션을 갱신
      return (
        <SessionContent.Provider value={{ session, status }}>
          {children}
        </SessionContent.Provider>
      );
    };
    
    // 클라이언트 컴포넌트용 커스텀 훅
    export const useSession = () => {
      return useContext(SessionContent);
    };

     

    활용할 때는 아래와 같이 사용하면 된다.

    import { useSession } from '@/hook/useSession';
    ...
      const { session, status } = useSession();
    ...

    3. Reference


    참고 1. Auth.js (NextAuth.js) 핵심 정리

     

Designed by Tistory.