[Next.js + supabase] 카카오 로그인 구현 (1)

ss_kim·2025년 2월 1일

카카오 소셜 로그인을 구현했던 과정을 기록

이번 글은 supabase에서 소셜 로그인을 할 수 있는지 모르고ㅜ 토큰을 발급받아 유저 정보를 반환 받는 과정까지만 구현한 내용이다.

supabase의 Auth Providers를 활용한 내용은 다음편에 작성할 예정


카카오 개발자 세팅

https://developers.kakao.com/docs/latest/ko/kakaologin/common

  1. 왼쪽의 설정하기 메뉴를 보면 카카오 로그인 활성화 설정, Redirect URI 등록은 필수 사항이라고 안내되어 있다.

    어플리케이션을 등록하고 내 어플리케이션 메뉴로 들어가서 설정해준다.

  1. 동의 항목 설정

    닉네임과 프로필 사진은 그냥 설정할 수 있지만 카카오계정(이메일)은 비즈니스 앱으로 등록되어 있어야 한다. (사업자 번호가 없다면 개인 개발자로 등록하면 됨)

  2. 플랫폼 메뉴에 도메인도 함께 등록


페이지 만들기

들어가기 전

로그인이 진행되는 과정을 살펴보면, 카카오 계정으로 로그인을 요청하면 카카오에서 Redirect URI로 인증 코드를 query parameter로 전달한다. 이 코드로 다시 카카오에 토큰을 발급받고, 토큰을 통해서 유저 정보를 가져올 수 있다.

✅ 카카오 로그인 과정은 인증 코드 받기 → 토큰 받기 → 유저 정보 받기 순차적으로 진행

구현 과정

  1. 카카오 계정으로 로그인 요청하고, 인증 코드 받기
    1-1 login 버튼 만들기

    /login/page.tsx
    
    const Login = () => {
      	// 카카오 REST API 키
    	const REST_API_KEY = process.env.NEXT_PUBLIC_KAKAO_LOGIN_REST_API_KEY;
        // 설정한 REDIRECT_URI
    	const REDIRECT_URI = process.env.NEXT_PUBLIC_KAKAO_LOGIN_REDIRECT_URI;
    	// 로그인을 요청할 주소
      	const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}`;
      	
      	return (
        	<Link href={KAKAO_AUTH_URL}>
        		<Image
          		  src={'/kakao_login_medium_wide.png'}
          		  alt='카카오 로그인 이미지'
          		  width={300}
          		  height={45}
       		    />
      		</Link>
        );
    }

    Kakao에서 제공하는 로그인 버튼 디자인을 참고해서 만들도록 하자
    https://developers.kakao.com/docs/latest/ko/kakaologin/design-guide

    1-2 Redirect URI에서 인증 코드 확인하기

    • 인증 코드는 REDIRECT_URI?code=#### 식으로 전달 받는다. (http://localhost:3000/auth/callback/kakao?code=####)
    • useSearchParams를 이용해 query parameter를 받아온다.
    /auth/callback/kakao/page.tsx
    
    const LoginRedirection = () => {
    	const router = useRouter();
    	const authCode = useSearchParams().get('code');
        console.log(authCode);
      
      	return (
    	  <div>
      		<h2>loading...</h2>
    	  </div>
    );

  1. 인증 코드를 전달해 토큰 발급 받기
    2-1 카카오에 인증 코드를 보내서 토큰 받는 함수 만들기

    /api/login.ts
    
    export const getKakaoLoginToken = async (code: string) => {
    	const tokenUrl = 'https://kauth.kakao.com/oauth/token';
    	const REST_API_KEY = process.env.NEXT_PUBLIC_KAKAO_LOGIN_REST_API_KEY;
    	const REDIRECT_URI = process.env.NEXT_PUBLIC_KAKAO_LOGIN_REDIRECT_URI;
    
    	const params = new URLSearchParams({
    		grant_type: 'authorization_code',
    		client_id: REST_API_KEY!,
    		redirect_uri: REDIRECT_URI!,
    		code: code,
    	});
    
    	try {
    		const response = await fetch(tokenUrl, {
      			method: 'POST',
      			headers: {
        			'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
      			},
      			body: params,
    		});
    
    		if (!response.ok) {
      			throw new Error(`${response.status}`);
    		}
    
    		const data = await response.json();
    
    		return data;
    	} catch (error) {
    		console.error(error);
    	}
    };

    2-2 Redirect URI 페이지가 렌더링될 때 위에서 만든 토큰 발급 함수를 실행 시키고 로컬 스토리지에 저장하기

    /auth/callback/kakao/page.tsx
    
    useEffect(() => {
    	const fetchLoginToken = async (code: string) => {
      		if (typeof code === 'string') {
        		try {
          			const data = await getKakaoLoginToken(code);
    
          			localStorage.setItem('token', JSON.stringify(data));
    
          			return data;
        		} catch (error) {
          			console.error(error);
        		}
      		}
    	};
      
        const handleLogin = async (code: string) => {
      		try {
        		// 토큰 받기
        		const token = await fetchLoginToken(code);
      		} catch (error) {
        		console.error(error);
      		}
    	};
    
    	if (authCode) {
      		handleLogin(authCode);
    	}
    }, [authCode, router]);

  1. 발급 받은 토큰으로 유저 정보 받기
    3-1 카카오에 토큰 보내서 유저 정보 받는 함수 만들기

    /api/login.ts
    
    export interface Token {
        token_type?: string;
      	access_token: string;
      	refresh_token?: string;
      	id_token?: string;
      	expires_in?: number;
      	refresh_token_expires_in?: string;
      	scope?: string;
     	token?: string;
        id?: number;
      	}
    
    export const getKakaoUserInfo = async ({ access_token }: Token) => {
    	const userInfoUrl = 'https://kapi.kakao.com/v2/user/me';
    
    	try {
    		const response = await fetch(userInfoUrl, {
      			method: 'GET',
      			headers: {
        			Authorization: `Bearer ${access_token}`,
        			'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
      			},
    		});
    
    		if (!response.ok) {
      			throw new Error(`${response.status}`);
    		}
    
    		const data = await response.json();
    
    		return data;
    	} catch (error) {
    		console.error(error);
    	}
    };

    3-2 Redirect URI 페이지 렌더링 후 토큰 발급 받고 나서 유저 정보를 요청하고 로컬 스토리지에 저장하기

    /auth/callback/kakao/page.tsx
    
    useEffect(() => {
        const fetchUserInfo = async (token: Token) => {
      		try {
       			const data = await getKakaoUserInfo(token);
    
        		localStorage.setItem('userInfo', JSON.stringify(data));
    
        		return data;
      		} catch (error) {
        		console.error(error);
      		}
    	};
      
      	const handleLogin = async (code: string) => {
      		try {
        		// 토큰 받기
        		const token = await fetchLoginToken(code);
    
        		// 유저 정보 받기
        		if (token) {
          			await fetchUserInfo(token);
        		}
    
      		} catch (error) {
        		console.error(error);
      		}
    	};
    
    	if (authCode) {
      		handleLogin(authCode);
    	}
    }, [authCode, router]);

위에서 전달 받은 유저 정보로 supabase의 user 테이블에 저장하면 될 듯하다.

다음 편에서는 Next.js의 route와 supabase의 Auth Provider를 이용해서 간단하게 로그인하고 트리거로 public.user 테이블에 데이터를 생성하는 방법을 알아보자.

profile
프론트엔드 개발자

0개의 댓글