Back-End/Supabase

Next.js + Supabase로 시작하는 인증 및 DB 연동

봉의일상 2025. 5. 7. 15:07

Next.js에서 Supabase를 활용해 인증 및 데이터베이스 연동을 시작하는 방법을 단계별로 정리한 글입니다.

Supabase는 Firebase의 오픈소스 대안으로, Postgres 기반의 데이터베이스와 인증, 스토리지 기능을 제공합니다.


프로젝트 준비

1. Supabase 프로젝트 생성

  1. https://supabase.com에 가입 및 로그인
  2. New Project 클릭 후 프로젝트 생성 (비밀번호는 꼭 기억)
  3. 생성 후 Settings > API에서 다음 정보 확인:
    • Project URL
    • anon/public API key

2. Next.js 프로젝트 설정

npx create-next-app@latest next-supabase-demo
cd next-supabase-demo
npm install @supabase/supabase-js

3. Supabase 클라이언트 설정

lib/supabaseClient.ts 파일 생성:

import { createClient } from '@supabase/supabase-js'

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!

export const supabase = createClient(supabaseUrl, supabaseAnonKey)

.env.local 파일:

NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key

소셜 로그인, 직접 구축할까?

Supabase는 Google, GitHub, Facebook 등의 OAuth 기반 소셜 로그인을 기본 제공하지만, 실무에서는 사용자 정보와 인증 흐름을 직접 제어할 수 있는 커스터마이징이 더 바람직할 수 있습니다.

소셜 로그인 Provider 설정 예시

왜 직접 구현하는 게 좋을까?

  • 토큰 저장 및 갱신을 우리 서비스에서 직접 제어 가능
  • 사용자 정보를 우리 DB 테이블에 명확히 저장 가능
  • 고급 기능 (예: 친구 목록, 캘린더 접근 등) 연동 가능
  • 향후 SSO, 2FA 등의 확장에도 유리함

커스텀 OAuth 흐름 요약

[프론트] 로그인 버튼 클릭
  → /api/auth/kakao 등으로 리다이렉트
    → Kakao/Google에서 로그인
      → access_token 반환
        → 백엔드에서 사용자 정보 저장 + 세션 발급

예제 코드: Kakao OAuth (API Route)

// pages/api/auth/kakao/callback.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import axios from 'axios'
import { supabase } from '@/lib/supabaseClient'

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const code = req.query.code as string

  const { data: tokenRes } = await axios.post(
    'https://kauth.kakao.com/oauth/token',
    new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: process.env.KAKAO_CLIENT_ID!,
      redirect_uri: process.env.KAKAO_REDIRECT_URI!,
      code,
      client_secret: process.env.KAKAO_CLIENT_SECRET!,
    }),
    { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
  )

  const kakaoAccessToken = tokenRes.access_token

  const { data: userRes } = await axios.get('https://kapi.kakao.com/v2/user/me', {
    headers: { Authorization: `Bearer ${kakaoAccessToken}` },
  })

  const kakaoUser = userRes

  await supabase.from('users').upsert({
    id: kakaoUser.id,
    email: kakaoUser.kakao_account.email,
    nickname: kakaoUser.properties.nickname,
    provider: 'kakao',
  })

  res.redirect('/')
}

테이블 생성 및 연동

예시: todos 테이블 생성

테이블 생성 및 필드 구성 예시

  • 필드: id, title, is_done, user_id
  • RLS (Row-Level Security) 설정 후 다음 정책 추가:
create policy "Users can view own todos"
on todos for select
using (auth.uid() = user_id);

프론트엔드 연동 예시:

const { data, error } = await supabase
  .from('todos')
  .select('*')
  .eq('user_id', user.id)

await supabase.from('todos').insert([
  { title: '블로그 쓰기', is_done: false, user_id: user.id }
])

테이블 생성 및 연동

아래는 Supabase SQL Editor나 초기 설정 시 사용할 수 있는 회원 및 할 일 테이블 생성 쿼리 예시입니다.

회원 테이블: users

create table if not exists users (
  id bigint primary key,
  email text unique not null,
  nickname text,
  provider text,
  created_at timestamp with time zone default timezone('utc'::text, now())
);

할 일 테이블: todos

create table if not exists todos (
  id bigint generated always as identity primary key,
  title text not null,
  is_done boolean default false,
  user_id bigint references users(id),
  created_at timestamp with time zone default timezone('utc'::text, now())
);

RLS 정책 (todos)

alter table todos enable row level security;

create policy "Users can view own todos"
on todos for select
using (auth.uid()::bigint = user_id);

create policy "Users can insert their own todos"
on todos for insert
with check (auth.uid()::bigint = user_id);​
 

마무리 및 다음 단계

  • Supabase는 인증, DB, 스토리지, 실시간 기능까지 제공하는 매우 강력한 BaaS입니다.
  • 커스터마이징된 소셜 로그인은 더 나은 통제력과 확장성을 제공합니다.
  • Next.js와의 궁합도 좋아 SSR, SSG에서도 유연하게 사용할 수 있습니다.