14강: 인증
로그인 만들기
이제 "누구세요?"를 물어볼 차례예요
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 프로젝트를 그대로 사용해요.
- https://supabase.com/dashboard 에 로그인해요
- 12강에서 만든 프로젝트를 선택해요
- 왼쪽 메뉴에서 Authentication 을 클릭해요
- 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 을 열어보세요.
- 이메일과 비밀번호를 입력하고 회원가입 을 눌러요
- Supabase에서 확인 이메일이 올 수도 있어요 (개발 중에는 대시보드에서 이메일 확인을 끌 수 있어요)
- 로그인하면
/todos페이지로 이동해요 - 할 일을 추가해 보세요. 이제 이 할 일은 내 계정에만 연결돼요
- 로그아웃하고, 다른 이메일로 회원가입해서 로그인해 보세요. 아까 추가한 할 일이 안 보이면 성공이에요
잘 되면 커밋해 두세요.
# ── 4. 커밋 ──
! git add .
! git commit -m "Supabase Auth 로그인/회원가입 + RLS 적용"
보안, 이것만 기억하세요
인증을 다루면 보안 이야기가 빠질 수 없어요. 하지만 깊이 들어가면 끝이 없으니, 바이브 코더가 꼭 알아야 할 것만 정리할게요.
비밀번호는 Supabase가 알아서 해요
사용자가 입력한 비밀번호를 그대로 저장하면 큰일 나요. 누군가 데이터베이스를 들여다보면 비밀번호가 다 보이니까요. 그래서 해싱(Hashing, 원본을 알 수 없게 뒤섞는 것)이라는 기술을 써요. Supabase Auth를 쓰면 이걸 자동으로 해줘요. 우리가 따로 할 일은 없어요.
HTTPS는 Vercel이 알아서 해요
HTTPS(데이터를 암호화해서 주고받는 통신 방식)는 로그인 정보가 중간에 도청당하지 않도록 보호해줘요. 16강에서 배울 Vercel에 배포하면 자동으로 HTTPS가 적용돼요. 이것도 우리가 따로 할 일이 없어요.
우리가 직접 챙겨야 할 3가지
- API 키를 코드에 직접 쓰지 마세요. 12강에서 배운 대로
.env.local파일에 넣어야 해요 - RLS를 반드시 켜세요. RLS를 안 켜면 로그인해도 남의 데이터가 보여요. 도어락 없는 아파트나 마찬가지예요
- 사용자 입력을 그대로 믿지 마세요. 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에게 붙여넣을 줄만 알면 돼요.
이번 강에서 기억할 것
핵심만 정리해 볼게요.
-
인증은 놀이공원 입장 팔찌예요. 로그인(팔찌 받기)해야 서비스의 기능(놀이기구)을 쓸 수 있어요. 로그아웃은 팔찌를 반납하는 거예요.
-
RLS는 아파트 도어락이에요. 로그인(건물 출입)과는 별개로, 내 데이터(내 집)는 나만 열 수 있어요.
auth.uid() = user_id한 줄이 도어락 역할을 해요. -
Supabase Auth 코드 패턴은 하나예요.
supabase.auth.동작()— signUp(회원가입), signInWithPassword(로그인), signOut(로그아웃), getUser(내 정보). 실제 코드는 Claude가 만들어줘요. -
소셜 로그인은 대리 인증이에요. 구글이나 카카오가 "이 사람 확인했어요"라고 보증해주는 거예요. Supabase가 연결을 다 처리해줘요.
-
보안은 3가지만 기억하세요. API 키 코드에 안 쓰기, RLS 반드시 켜기, 입력값 검증하기. 나머지는 Supabase와 Vercel이 해줘요.
이런 분께 추천해요
인증은 "내 서비스에 회원 기능을 넣고 싶은 분"을 위한 필수 단계예요.
- 할 일 목록, 가계부, 일기장처럼 개인 데이터를 다루는 서비스를 만드는 분 — 로그인이 없으면 모든 데이터가 공개돼요. 인증을 붙여야 "내 데이터는 나만" 볼 수 있어요.
- 팀원이나 고객별로 다른 화면을 보여주고 싶은 분 — "누가 로그인했느냐"에 따라 보이는 데이터와 기능을 다르게 할 수 있어요. DGHR처럼요.
- "카카오로 로그인", "구글로 로그인" 버튼을 넣고 싶은 분 — Supabase Auth가 소셜 로그인 연결을 다 처리해줘요. 직접 만드는 건 상상 이상으로 복잡해요.
참고 링크
- Supabase Auth 공식 문서
- Supabase 이메일/비밀번호 인증 가이드
- Supabase 소셜 로그인(OAuth) 가이드
- Supabase Google OAuth 설정
- Supabase RLS(Row Level Security) 가이드
- Supabase JavaScript 클라이언트 - Auth
- Next.js + Supabase Auth 퀵스타트
▸개정 이력1건
- v12026-04-12초판
이 글이 도움이 되었나요?