0261

FE

[Next.js] Next.js 기반 프로젝트에 소셜 로그인 붙이기 (NextAuth 실전 가이드)

오프닝

Next.js 기반 프로젝트에서 소셜 로그인을 사용하고 싶었다. Next.js에서는 자체적인 Auth기반 패키지를 지원하고 있고, 이를 통해 보다 간편하게 소셜 로그인을 구현할 수 있었다. 오늘은 Next.js 기반에서 소셜 로그인을 NextAuth로 구현하는 방법에 대해서 살펴보자.

1. NextaAuth 패키지 설치

JavaScript
npm install next-auth @auth/core

2. 구글 클라우드 콘솔

1) Google Cloud Console 접속

2) 왼쪽 상단의 '프로젝트 선택'

3) 오른쪽 상단의 '새 프로젝트'

4) 프로젝트 이름 입력 후 '만들기'

5) 'API 및 서비스' 클릭

6) '사용자 인증 정보' 클릭

7) 우측의 '동의 화면 구성' 클릭

8) '시작하기' 클릭

9) 기본 정보 내용 입력 후 '만들기'

10) '사용자 인증 정보 만들기' -> 'OAuth 클라이언드 ID' 클릭

11) 애플리케이션 유형, 이름 입력 후 '만들기'

12) 발급된 클라이언트 ID, 클라이언트 보안 비밀번호 저장하기(복사 또는 JSON 다운로드)

13) 승인된 리디렉션 URI에 http://localhost:3000/api/auth/callback/google를 ㅇ

3. env.local를 src 폴더와 같은 위치에 생성 후 아래와 같이 내용 작성

JavaScript
GOOGLE_CLIENT_ID=발급받은_CLIENT_ID
GOOGLE_CLIENT_SECRET=발급받은_CLIENT_SECRET
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=랜덤한_문자열(예: openssl rand -base64 32 로 생성)

4. routes.ts 파일 생성 후 아래와 같이 내용 작성

JavaScript
// /src/app/api/auth/[...nextauth]/route.ts

import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";

const handler = NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
  ],
  callbacks: {
    async session({ session, token }) {
      session.user.id = token.sub;
      return session;
    },
  },
});

export { handler as GET, handler as POST };

?? /src/app/api/auth/[...nextauth]/route.ts 파일이란?해당 파일은 NextAuth에서 소셜 로그인 및 세션 인증을 처리하는 핵심 API 라우트 파일이다.이 파일을 통해 NextAuth가 Google, GitHub 같은 외부 인증 서비스와의 OAuth 인증 과정을 처리하고, 로그인 이후 세션을 생성하거나 유지하는 작업을 수행한다.Next.js의 App Router에서는 API 라우트를 만들 때 /api/ 경로 하위에 위치시키며, [...nextauth]라는 이름을 사용해야 NextAuth 내부에서 해당 라우트를 인식하고 동작한다.즉, 이 파일은 소셜 로그인 요청, 인증 콜백 처리, 세션 관리, JWT 발급 등의 모든 인증 흐름의 엔드포인트 역할을 한다.NextAuth를 사용할 때 반드시 필요한 설정 파일이며, 여기서 Provider 설정, 콜백 함수(custom session, JWT 설정 등)를 통해 서비스에 맞게 인증 로직을 커스터마이징할 수 있다.

5. next-auth.d.ts 파일 생성 후 아래와 같이 작성

JavaScript
// /src/type/next-auth.d.ts

import NextAuth from "next-auth";

declare module "next-auth" {
    interface Session {
        user: {
            id: string;
            name?: string | null;
            email?: string | null;
            image?: string | null;
        };
    }

    interface User {
        id: string;
        name?: string | null;
        email?: string | null;
        image?: string | null;
    }
}

?? /src/types/next-auth.d.ts 파일이란?해당 파일은NextAuth의 기본 타입을 확장(augment)하기 위해 사용하는 선언 파일이다. NextAuth가 기본적으로 제공하는 session.user 타입에는 name, email, image만 정의되어 있어, 프로젝트에서 필요한 추가 속성(예: id, role, nickname 등)을 직접 선언해주지 않으면 타입스크립트가 오류를 발생시킨다. 이를 해결하기 위해 next-auth.d.ts 파일을 만들고, NextAuth 모듈을 확장하여 session.user에 필요한 속성을 추가로 정의하는 것이다. 이렇게 하면 session.user.id와 같이 커스텀 속성을 사용할 때 타입스크립트가 오류를 내지 않고, 안전하게 코드 자동완성 및 타입 추론이 가능해진다. 타입스크립트 프로젝트에서 NextAuth를 사용할 때는 이런 타입 확장이 필수적인 작업이다.

5. AuthProvider.tsx 생성 후 아래와 같이 내용 작성

JavaScript
// src/components/AuthProvider.tsx
'use client';

import {SessionProvider} from "next-auth/react";

export default function AuthProvider({children} : {
    children: React.ReactNode
}) {
    return <SessionProvider>{children}</SessionProvider>;
}

6. layout.tsx 파일에 AuthProvider로 children 감싸기

7. LoginButton.tsx 파일 생성 후 아래와 같이 작성

JavaScript
'use client';

import {signIn, signOut, useSession} from "next-auth/react";

export default function LoginButton() {
    const {data: session} = useSession();

    if (session) {
        return (
            <button onClick={() => signOut()}>
                로그아웃 ({
                    session.user
                        ?.name
                })
            </button>
        );
    }

    return <button onClick={() => signIn('google')}>Google로 로그인</button>;
}

8. 원하는 페이지에 LoginButton 컴포넌트 사용 (예시 : Header.tsx)

JavaScript
import Image from "next/image";
import LoginButton from "../LoginButton";

function Header() {
    
    return (
        <div className="flex justify-space py-2">
            <Image src="/img/logo/CoMe_Logo_Full_Row2.png" width={100} height={60} alt="come logo" />
            <LoginButton/>
        </div>
    )
}

export default Header;

9. 로그인 확인

https://play-tv.kakao.com/embed/player/cliplink/456985645?service=daum_tistory

로그인 버튼을 누르게 되면, 구글 로그인 모달창으로 이동하게 되고, 로그인을 성공하면 세션을 유지하게 된다.

새로고침을 하더라도 세션은 유지되며, 로그아웃 버튼을 누르면 로그아웃하게 된다.

10. 세션의 유효시간 지정

JavaScript
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";

const handler = NextAuth({
    providers: [GoogleProvider({
            clientId: process.env.GOOGLE_CLIENT_ID !,
            clientSecret: process.env.GOOGLE_CLIENT_SECRET !
    })],
    session: {
        strategy: "jwt",  // JWT 기반 세션 사용
        maxAge: 60 * 60 * 24 * 7,  // 7일 (초 단위)
    },
    callbacks: {
        async session({session, token}) {
            if (session.user) {
                session.user.id = token.sub !;
            }
            return session;
        }
    }
});

export {
    handler as GET,
    handler as POST
};

기존의 route.ts 파일에서 session에 대한 내용만 추가해주면 된다.

마무리

이렇게 Next.js 기반의 프로젝트에 NextAuth를 활용한 구글 로그인 구현을 진행해보았다. 처음 NextAuth를 접했을 당시에는 next-auth.d.ts가 어떤 역할을 하는지, 왜 route.ts가 필요한지에 대해서 이해하기 보다는 기능 구현에 집중해서 Auth를 구현했었지만, 이번에는 하나하나 시도하고 공부하고 이유를 찾아가며 사용할 수 있어서 더욱 유익했던 것 같다.

생각보다 간단하면서도 많은 기능을 이용할 수 있는 NextAuth에 대해서 더 많은 공부를 해보고 싶다.