코디챗봇 프로젝트

[Aura_AI] [2편] App Router 환경에서 OAuth 인증 설계하기

frontend-diary-log 2026. 1. 23. 19:35

 

📘 [Aura_AI] [2편] App Router 환경에서 OAuth 인증 설계하기

— Google OAuth + Auth.js(v5)를 선택한 이유

안녕하세요.
Aura_AI 프로젝트 두 번째 기록입니다.

이번 글에서는
Next.js App Router 환경에서 Google OAuth 인증을 어떻게 설계했는지,
그리고 단순 구현을 넘어 왜 이 구조를 선택했는지를 중심으로 정리합니다.

이번 단계의 목표는 단순했습니다.

“로그인이 되는 것”이 아니라
App Router 환경에서 확장 가능한 인증 구조를 만드는 것


🎯 Day 7 목표

  • Google 로그인 버튼 클릭 → OAuth 인증 성공
  • 인증 후 유저 정보를 세션에 안전하게 저장
  • App Router 환경에서 Hydration 오류 없이 안정적으로 동작
  • 로그인 성공 시 /chat 페이지로 리다이렉트

✅ 결과 요약

  • Google OAuth 로그인 성공
  • 로그인 후 /chat 정상 이동
  • session.user.id 접근 가능
  • Day 8(Zustand, middleware)로 바로 확장 가능한 상태 완성

1. 왜 OAuth 인증을 먼저 설계했을까?

Aura_AI는 개인화된 추천 서비스입니다.
즉, 유저의 상태를 기준으로 서비스 흐름이 달라집니다.

  • 로그인 여부
  • 유저 식별자(id)
  • 이후 저장될 취향 / 위치 / 기록

이런 서비스에서 인증은 “부가 기능”이 아니라
모든 기능의 출발점입니다.

그래서 UI보다 먼저
인증 흐름과 세션 구조부터 설계하는 것을 Day 7의 목표로 잡았습니다.


2. 왜 Google OAuth인가?

처음부터 ID/PW 회원가입을 만들 수도 있었지만,
Day 7에서는 OAuth를 우선 선택했습니다.

이유는 명확합니다.

  • 실제 서비스에서 가장 많이 쓰이는 인증 방식
  • 비밀번호 관리 부담 없음
  • 빠른 온보딩 → 서비스 진입 장벽 최소화
  • 이후 자체 회원가입과 병행 설계 가능

👉 즉, OAuth는 “편의성”이 아니라
서비스 초기 진입 전략입니다.


3. App Router 환경에서 Auth.js(v5)를 선택한 이유

npm install next-auth@beta

Next.js App Router 환경에서는
**Auth.js v5(beta)**가 사실상 정석에 가깝습니다.

v5를 선택한 이유

  • App Router 구조와 자연스럽게 맞음
  • handlers(GET / POST) 기반 API 설계
  • 인증 로직을 auth.ts 한 파일로 집중 관리
  • 이후 DB Adapter, middleware 확장이 쉬움

👉 “지금은 OAuth지만,
나중에 인증 서버로 확장 가능한 구조”를 만들기 위함입니다.


4. auth.ts는 ‘설정 파일’이 아니다

Day 7에서 가장 중요했던 파일은 auth.ts입니다.

이 파일은 단순한 Google 로그인 설정 파일이 아니라
인증 상태 흐름(JWT → Session)을 설계한 핵심 파일입니다.

auth.ts가 담당하는 역할

  • Google OAuth Provider 설정
  • JWT 생성 및 관리
  • 클라이언트 Session 구조 정의
  • /api/auth/* 요청의 실제 처리 로직
// /auth.ts
import NextAuth from "next-auth";
import Google from "next-auth/providers/google";

export const {
  handlers: { GET, POST },
  auth,
  signIn,
  signOut,
} = NextAuth({
  providers: [
    Google({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
  ],
  callbacks: {
    async jwt({ token, user }) {
      if (user) token.id = user.id;
      return token;
    },
    async session({ session, token }) {
      if (session.user) {
        session.user.id = token.id as string;
      }
      return session;
    },
  },
});

5. 왜 JWT → Session 구조로 설계했을까?

❌ 단순한 방식

session.user.id = user.id;
  • 로그인 직후엔 동작
  • 새로고침 / SSR 이후 user 없음 → ❌

✅ 현재 구조 (정석)

user (로그인 시)
 → jwt (서버 인증 상태)
   → session (클라이언트 전달)

이 구조의 장점

  • 새로고침에도 인증 정보 유지
  • SSR / CSR 환경 모두 안정적
  • middleware, Zustand와 자연스럽게 연결 가능

👉 **서버 기준 인증 상태(JWT)**와
**클라이언트 사용 세션(Session)**을 명확히 분리한 설계입니다.


6. App Router에서 Auth API를 연결하는 방식

App Router에서는
HTTP 메서드 기반으로 API를 정의합니다.

// app/api/auth/[...nextauth]/route.ts
export { GET, POST } from "@/auth";

이 파일은 로직을 구현하지 않습니다.

의미는 단 하나입니다.

“auth.ts에서 이미 만들어진
GET / POST 인증 핸들러를
이 경로에 그대로 연결한다.”

이 구조 덕분에:

  • 인증 로직은 auth.ts에 집중
  • API Route는 얇고 단순
  • 재사용성과 확장성이 좋아집니다

7. Providers를 분리한 이유 (Hydration 오류 해결)

App Router에서
layout.tsx는 서버 컴포넌트로 유지하는 것이 핵심입니다.

그래서 클라이언트 전용 상태(Session, Theme)는
별도의 providers.tsx로 분리했습니다.

// app/providers.tsx
"use client";

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

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <SessionProvider>
      <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
        {children}
      </ThemeProvider>
    </SessionProvider>
  );
}
// app/layout.tsx
<html lang="ko" suppressHydrationWarning>
  <body>
    <Providers>{children}</Providers>
  </body>
</html>

이렇게 나눈 이유

  • Server / Client 경계 명확화
  • App Router 철학 유지
  • Theme 변경으로 인한 hydration 오류 방지
  • Provider 확장에 유리한 구조

8. Day 7에서 실제로 겪은 문제들

  • 환경 변수 이름 불일치 → OAuth 실패
  • AUTH_SECRET에 명령어 문자열 그대로 입력 → 인증 오류
  • Theme class mismatch → hydration warning
  • button 중첩 → 서버/클라이언트 DOM 불일치

👉 이 문제들을 해결하며
“왜 이런 구조가 정석인지”를 몸으로 이해할 수 있었습니다.


마치며

Day 7은
“로그인 기능을 붙인 날”이 아니라,

App Router 환경에서 인증을 어떻게 설계해야 하는지
기준을 세운 날
이었습니다.

이 구조를 기반으로
다음 단계에서는:

  • Zustand 전역 상태 관리
  • OAuth 유저 / 일반 유저 통합
  • 인증 기반 라우트 보호(middleware)

로 자연스럽게 확장할 예정입니다.


🔜 다음 편 예고

📘 [Aura_AI] [3편] OAuth vs 자체 회원가입 — 서비스에 맞는 인증 전략