본문으로 건너뛰기

14강: 인증

v1
작성 2026-04-12읽는 시간 10

로그인 만들기

이제 "누구세요?"를 물어볼 차례예요

12강에서 Supabase로 데이터베이스(인터넷 창고)를 만들었어요. 13강에서는 API(주문 창구)로 남의 데이터를 가져다 쓰는 법도 배웠고요.

그런데 한 가지 문제가 있어요.

지금 만든 할 일 목록을 떠올려 보세요. 누구든 접속하면 모든 할 일이 다 보여요. 내가 적은 할 일을 옆집 사람도 볼 수 있고, 옆집 사람이 적은 것도 내게 보여요. 심지어 남의 할 일을 삭제할 수도 있어요.

현실에서 이러면 곤란하죠? 내 다이어리를 아무나 열어볼 수 있다면요.

그래서 인증(Authentication, 이 사람이 누구인지 확인하는 과정)이 필요해요. "누가 쓰고 있는지"를 알아야, "내 데이터는 나만" 보여줄 수 있어요.


이건 뭐예요?

인증 = 놀이공원 입장 팔찌

인증을 놀이공원에 비유해 볼게요.

놀이공원에 들어가려면 매표소에서 입장 팔찌를 받아야 해요. 팔찌 색깔에 따라 탈 수 있는 놀이기구가 다르죠. 자유이용권 팔찌가 있으면 모든 놀이기구를 탈 수 있고, 기본권 팔찌는 일부만 가능해요. 팔찌가 없으면 아예 입장을 못 하고요.

웹 서비스도 완전히 같아요.

놀이공원웹 서비스
매표소로그인/회원가입 페이지
입장 팔찌세션 토큰(Session Token, 로그인 상태를 증명하는 열쇠)
팔찌 색깔권한(Role, 어디까지 할 수 있는지)
팔찌 검사 직원서버의 인증 확인 로직
놀이기구서비스의 기능과 데이터

로그인은 매표소에서 팔찌를 받는 행위예요. 로그아웃은 팔찌를 반납하는 거예요. 그리고 놀이기구(기능)를 탈 때마다 직원(서버)이 팔찌(토큰)를 확인해요.

RLS = 아파트 도어락

데이터를 보호하는 개념도 하나 더 있어요. RLS(Row Level Security, 행 단위 보안)라는 거예요.

아파트를 생각해 보세요. 현관문에 공동 비밀번호가 있어서 입주민은 건물에 들어올 수 있어요. 그런데 각 집에는 도어락이 따로 있잖아요? 내 집 열쇠로는 내 집만 열 수 있고, 옆집 문은 열 수 없어요.

RLS도 같아요.

  • 아파트 현관 비밀번호 = 로그인 (서비스에 들어올 수 있는지)
  • 각 집의 도어락 = RLS (내 데이터만 볼 수 있는지)

로그인만으로는 부족해요. 로그인했다고 다른 사람 데이터까지 보이면 안 되니까요. RLS가 "이 데이터는 이 사람 거니까, 이 사람만 볼 수 있게"를 자동으로 걸어줘요.

소셜 로그인 = 대리 인증

소셜 로그인(Social Login)은 이미 다른 서비스에서 인증한 정보를 빌려 쓰는 거예요.

새 쇼핑몰에 회원가입할 때 "카카오로 로그인", "구글로 로그인" 버튼 본 적 있죠? 이건 카카오나 구글이 "이 사람, 우리가 이미 확인했어요. 믿어도 돼요"라고 보증해주는 거예요. 마치 친구가 "얘 내 친구야, 괜찮은 사람이야"라고 소개해주는 것과 비슷해요.

장점은 명확해요.

  • 사용자는 새 비밀번호를 또 만들 필요 없어요
  • 개발자는 복잡한 인증 시스템을 직접 만들 필요 없어요
  • Supabase가 구글, 카카오, GitHub 등과의 연결을 전부 처리해줘요

우리는 이렇게 쓰고 있어요

AI//STUDY 사이트는 누구나 읽을 수 있는 공개 아카이브라서 로그인이 필요 없어요. 하지만 디온웍스의 다른 서비스들은 인증이 핵심이에요.

  • DGHR(디지HR) — 카카오 소셜 로그인으로 직원 인증을 해요. 로그인하면 내 출퇴근 기록만 보여요. 다른 직원의 기록은 볼 수 없어요. 이게 바로 RLS예요. 관리자 계정으로 로그인하면 모든 직원의 기록을 볼 수 있고요. 같은 테이블, 같은 데이터인데 "누가 로그인했느냐"에 따라 보이는 게 달라져요.
  • HoneyERP(허니이알피) — 이메일/비밀번호 로그인을 써요. 거래처 정보, 견적서, 발주서 같은 민감한 데이터가 있으니까, 로그인 없이는 아무것도 볼 수 없어요. 여기도 RLS로 각 사업장의 데이터를 분리하고 있어요.

12강에서 만든 할 일 목록에 인증을 붙이면, "내 할 일은 나만 보이는" 진짜 서비스가 돼요. 오늘 그걸 해볼 거예요.


한번 써볼까요?

오늘 실습은 세 단계로 나눠요.

  • 1단계: Supabase 대시보드에서 인증 설정 켜기
  • 2단계: 로그인/회원가입 페이지 만들기
  • 3단계: RLS로 "내 데이터만 보이게" 만들기

1단계: Supabase 인증 설정

12강에서 만든 Supabase 프로젝트를 그대로 사용해요.

  1. https://supabase.com/dashboard 에 로그인해요
  2. 12강에서 만든 프로젝트를 선택해요
  3. 왼쪽 메뉴에서 Authentication 을 클릭해요
  4. Providers 탭에서 Email 이 이미 활성화되어 있는지 확인해요 (기본적으로 켜져 있어요)

이메일/비밀번호 인증은 기본으로 켜져 있어요. 이것만으로도 회원가입과 로그인이 가능해요.

소셜 로그인(구글, 카카오 등)은 각 서비스의 개발자 콘솔에서 별도로 설정해야 해요. 오늘은 이메일/비밀번호 로그인에 집중하고, 소셜 로그인은 다음에 도전해도 돼요.

2단계: todos 테이블에 사용자 연결하기

12강에서 만든 todos 테이블에 "이건 누구 할 일인지"를 기록할 열을 추가해야 해요.

Supabase 대시보드의 SQL Editor 에서 아래 코드를 실행해요.

-- todos 테이블에 사용자 ID 열 추가
ALTER TABLE todos ADD COLUMN user_id uuid REFERENCES auth.users DEFAULT auth.uid();

-- RLS 활성화 (행 단위 보안 켜기)
ALTER TABLE todos ENABLE ROW LEVEL SECURITY;

-- 정책 만들기: 로그인한 사용자는 자기 데이터만 볼 수 있음
CREATE POLICY "본인 데이터만 조회" ON todos
FOR SELECT USING (auth.uid() = user_id);

-- 정책 만들기: 로그인한 사용자는 자기 이름으로만 데이터를 추가할 수 있음
CREATE POLICY "본인 데이터만 추가" ON todos
FOR INSERT WITH CHECK (auth.uid() = user_id);

-- 정책 만들기: 로그인한 사용자는 자기 데이터만 수정할 수 있음
CREATE POLICY "본인 데이터만 수정" ON todos
FOR UPDATE USING (auth.uid() = user_id);

-- 정책 만들기: 로그인한 사용자는 자기 데이터만 삭제할 수 있음
CREATE POLICY "본인 데이터만 삭제" ON todos
FOR DELETE USING (auth.uid() = user_id);

이 SQL이 하는 일을 풀어보면 이래요.

  • user_id — 각 할 일에 "이건 누가 만든 건지" 표시해요. auth.users는 Supabase가 자동으로 관리하는 사용자 테이블이에요
  • ENABLE ROW LEVEL SECURITY — 도어락을 켜는 거예요. 이제부터 아무나 데이터에 접근할 수 없어요
  • CREATE POLICY — 도어락의 규칙을 정하는 거예요. auth.uid() = user_id는 "지금 로그인한 사람의 ID와 데이터의 주인 ID가 같을 때만 허용"이라는 뜻이에요

3단계: 인증 코드 패턴 이해하기

Claude가 만들어줄 코드 안에는 이런 패턴이 들어있을 거예요. 외울 필요는 없지만 흐름을 알면 좋아요.

회원가입

// 새 계정 만들기
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'my-password-123',
})

로그인

// 이메일과 비밀번호로 로그인
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'my-password-123',
})

로그아웃

// 로그아웃 (팔찌 반납)
const { error } = await supabase.auth.signOut()

지금 누가 로그인 중인지 확인

// 현재 로그인한 사용자 정보 가져오기
const { data: { user } } = await supabase.auth.getUser()

패턴이 보이시죠? 전부 supabase.auth.동작() 으로 시작해요. 12강에서 supabase.from('todos').동작() 이었던 것과 구조가 같아요. from 대신 auth를 쓰는 것만 다를 뿐이에요.


클로드 코드 터미널에서는 이렇게

12강에서 만든 Next.js + Supabase 프로젝트에 로그인 기능을 추가하는 전체 흐름이에요.

# ── 1. 프로젝트 폴더로 이동 (일반 터미널에서) ──
cd ~/my-service

# ── 2. Claude Code 시작 ──
claude

Claude Code가 열리면, 먼저 로그인/회원가입 페이지를 만들어 달라고 해요.

클로드 코드 대화창에서 ! 를 맨 앞에 붙이면 터미널 명령어를 바로 실행할 수 있어요.

너는 10년차 풀스택 개발자야.
나는 코딩 1줄도 모르는 바이브 코더야.

Supabase Auth로 로그인/회원가입 기능을 만들어줘.

요구사항:
1. src/app/login/page.tsx에 로그인/회원가입 통합 페이지를 만들어줘
2. 이메일 + 비밀번호로 회원가입과 로그인을 할 수 있게 해줘
3. 로그인 상태면 /todos로 이동, 비로그인이면 /login으로 이동
4. 로그아웃 버튼도 만들어줘 (todos 페이지 상단에)
5. src/lib/supabase.ts는 이미 만들어져 있어 (12강에서 만든 것)

디자인:
- Tailwind CSS 사용
- 다크 배경, 밝은 글씨, 시안 포인트(#06b6d4)
- 이메일 입력칸, 비밀번호 입력칸, 로그인 버튼, 회원가입 버튼
- 모바일 반응형

안 할 것:
- 소셜 로그인은 지금 안 해 (나중에 추가할 거야)
- 다른 기존 파일은 건드리지 마 (todos 페이지에 로그아웃 버튼만 추가)
- 외부 라이브러리 추가하지 마

코드에 한글 주석 달아줘.

페이지가 만들어지면, todos 페이지도 로그인 사용자 전용으로 수정해야 해요.

todos 페이지를 로그인한 사용자만 쓸 수 있게 수정해줘.

수정 사항:
1. 페이지 로드 시 로그인 상태 확인 — 비로그인이면 /login으로 보내줘
2. 데이터 추가할 때 user_id를 자동으로 넣어줘
3. 데이터 조회할 때 user_id로 필터링해줘 (RLS가 걸려있지만 클라이언트에서도 필터)
4. 상단에 로그아웃 버튼 + 사용자 이메일 표시

안 할 것:
- login 페이지는 건드리지 마
- 디자인 큰 변경 하지 마 (기존 스타일 유지)

확인해 보세요.

# ── 3. 개발 서버 실행 ──
! npm run dev

브라우저에서 http://localhost:3000/login 을 열어보세요.

  1. 이메일과 비밀번호를 입력하고 회원가입 을 눌러요
  2. Supabase에서 확인 이메일이 올 수도 있어요 (개발 중에는 대시보드에서 이메일 확인을 끌 수 있어요)
  3. 로그인하면 /todos 페이지로 이동해요
  4. 할 일을 추가해 보세요. 이제 이 할 일은 내 계정에만 연결돼요
  5. 로그아웃하고, 다른 이메일로 회원가입해서 로그인해 보세요. 아까 추가한 할 일이 안 보이면 성공이에요

잘 되면 커밋해 두세요.

# ── 4. 커밋 ──
! git add .
! git commit -m "Supabase Auth 로그인/회원가입 + RLS 적용"

보안, 이것만 기억하세요

인증을 다루면 보안 이야기가 빠질 수 없어요. 하지만 깊이 들어가면 끝이 없으니, 바이브 코더가 꼭 알아야 할 것만 정리할게요.

비밀번호는 Supabase가 알아서 해요

사용자가 입력한 비밀번호를 그대로 저장하면 큰일 나요. 누군가 데이터베이스를 들여다보면 비밀번호가 다 보이니까요. 그래서 해싱(Hashing, 원본을 알 수 없게 뒤섞는 것)이라는 기술을 써요. Supabase Auth를 쓰면 이걸 자동으로 해줘요. 우리가 따로 할 일은 없어요.

HTTPS는 Vercel이 알아서 해요

HTTPS(데이터를 암호화해서 주고받는 통신 방식)는 로그인 정보가 중간에 도청당하지 않도록 보호해줘요. 16강에서 배울 Vercel에 배포하면 자동으로 HTTPS가 적용돼요. 이것도 우리가 따로 할 일이 없어요.

우리가 직접 챙겨야 할 3가지

  1. API 키를 코드에 직접 쓰지 마세요. 12강에서 배운 대로 .env.local 파일에 넣어야 해요
  2. RLS를 반드시 켜세요. RLS를 안 켜면 로그인해도 남의 데이터가 보여요. 도어락 없는 아파트나 마찬가지예요
  3. 사용자 입력을 그대로 믿지 마세요. Claude에게 코드를 만들어 달라고 할 때 "입력값 검증도 해줘"라고 한 마디 추가하면 돼요. 예를 들어 이메일 칸에 이메일 형식이 아닌 걸 넣으면 "올바른 이메일을 입력해주세요"라고 알려주는 거예요

나머지는 Supabase와 Vercel이 알아서 해줘요. 바이브 코더는 이 3가지만 잘 지키면 돼요.


PART 3을 마무리하며

14강까지 오느라 정말 수고하셨어요. PART 3(본격 개발)에서 어떤 걸 해왔는지 돌아볼게요.

배운 것한 줄 요약
10강수직 슬라이싱한 번에 하나씩, 매번 확인
11강프론트엔드 (Next.js)사용자가 보는 화면 만들기
12강백엔드 (Supabase DB)데이터를 저장하는 창고 만들기
13강API 연동남의 데이터를 가져다 쓰기
14강인증 (Supabase Auth)누가 쓰는지 구분하기

이제 여러분의 서비스에는 화면도 있고, 데이터베이스도 있고, 외부 API도 붙었고, 로그인까지 돼요. 진짜 서비스의 뼈대가 다 갖춰진 거예요.

다음은 PART 4: 검증 + 배포예요. 15강에서는 디버깅을 다뤄요. 지금까지 개발하면서 에러 메시지를 만난 적이 있을 거예요. 그 빨간 글씨가 무섭지 않아지는 법을 배워요. 에러 메시지를 읽을 줄 몰라도 괜찮아요. 복사해서 Claude에게 붙여넣을 줄만 알면 돼요.


이번 강에서 기억할 것

핵심만 정리해 볼게요.

  1. 인증은 놀이공원 입장 팔찌예요. 로그인(팔찌 받기)해야 서비스의 기능(놀이기구)을 쓸 수 있어요. 로그아웃은 팔찌를 반납하는 거예요.

  2. RLS는 아파트 도어락이에요. 로그인(건물 출입)과는 별개로, 내 데이터(내 집)는 나만 열 수 있어요. auth.uid() = user_id 한 줄이 도어락 역할을 해요.

  3. Supabase Auth 코드 패턴은 하나예요. supabase.auth.동작() — signUp(회원가입), signInWithPassword(로그인), signOut(로그아웃), getUser(내 정보). 실제 코드는 Claude가 만들어줘요.

  4. 소셜 로그인은 대리 인증이에요. 구글이나 카카오가 "이 사람 확인했어요"라고 보증해주는 거예요. Supabase가 연결을 다 처리해줘요.

  5. 보안은 3가지만 기억하세요. API 키 코드에 안 쓰기, RLS 반드시 켜기, 입력값 검증하기. 나머지는 Supabase와 Vercel이 해줘요.


이런 분께 추천해요

인증은 "내 서비스에 회원 기능을 넣고 싶은 분"을 위한 필수 단계예요.

  • 할 일 목록, 가계부, 일기장처럼 개인 데이터를 다루는 서비스를 만드는 분 — 로그인이 없으면 모든 데이터가 공개돼요. 인증을 붙여야 "내 데이터는 나만" 볼 수 있어요.
  • 팀원이나 고객별로 다른 화면을 보여주고 싶은 분 — "누가 로그인했느냐"에 따라 보이는 데이터와 기능을 다르게 할 수 있어요. DGHR처럼요.
  • "카카오로 로그인", "구글로 로그인" 버튼을 넣고 싶은 분 — Supabase Auth가 소셜 로그인 연결을 다 처리해줘요. 직접 만드는 건 상상 이상으로 복잡해요.

참고 링크

개정 이력1
  • v12026-04-12초판

이 글이 도움이 되었나요?