소개
이번 작업은 Supabase Auth와 Toss Payments를 각각 붙이는 일처럼 보였지만, 실제로는 사용자가 자연스럽게 로그인하고, 안전하게 결제까지 이어지는 흐름을 만드는 작업에 가까웠 습니다.
처음에는 기능 연결에 집중했지만, 구현을 하다 보니 더 중요한 건 따로 있었습니다.
로그인한 사용자는 바로 필요한 화면으로 갈 수 있어야 하고
로그인하지 않은 사용자는 자연스럽게 로그인으로 유도되어야 하며
결제는 성공 메시지보다 실제 권한 지급까지 정확히 반영되는 것이 더 중요했습니다
그래서 이번에는 인증과 결제를 각각 구현하는 데서 끝내지 않고, 서비스 흐름 전체를 안정적으로 정리하는 것을 목표로 잡았습니다.
진행 방법
1. Supabase Auth 로그인 흐름 정리
로그인 화면에서는 Google, Kakao OAuth 로그인을 사용했습니다.
supabase.auth.signInWithOAuth({ provider: 'google' })
supabase.auth.signInWithOAuth({ provider: 'kakao' })흐름은 아래처럼 구성했습니다.
[login/page.tsx]
supabase.auth.signInWithOAuth({ provider: 'google' or 'kakao' })
│
└── 리디렉션 → /api/auth/callback
│
└── supabase.auth.exchangeCodeForSession(code)
└── 성공 → / → /home핵심은 클라이언트에서 로그인 시작 → 서버 콜백에서 세션 확정 구조로 정리한 점입니다.
이렇게 해두니 이후 인증 상태를 제어하기가 훨씬 명확했습니다.
2. Toss Payments 결제 위젯 연동
한국 모바일 앱 스크린샷
상품은 lib/toss/plans.ts에서 명시적으로 정의했습니다.
planType
상품명
가격
지급 내용
유효기간
scan5
마미스캔 5회 추가권
1,800원
scan_credits +5
+14일
monthly
마미스캔 1개월 무제한 이용권
5,800원
subscription_status = active
+30일
3. /api/payment/confirm에서 서버 검증
결제 승인 API에서는 아래 순서로 처리했습니다.
orderId에서planType파싱서버 기준 금액 검증
Supabase Auth로 현재 사용자 확인
transactions에서 중복 결제 체크Toss 결제 승인 요청
성공 시 DB 반영
transactions에 이력 저장
5. 보안 처리
이번 구현에서는 아래 보안 기준을 꼭 지키려고 했습니다.
TOSS_SECRET_KEY는 서버 전용으로 관리금액은 프론트 값이 아니라 서버 기준으로 재검증
orderId중복 체크 + unique constraint로 중복 결제 방지
기능은 붙이기 쉬워 보여도, 인증과 결제는 결국 신뢰를 다루는 영역이라서 서버 기준 검증이 특히 중요했습니다.
결과와 배운 점
이번 작업을 하면서 가장 크게 느낀 건, 로그인과 결제는 각각의 기능이 아니라 서비스 경험의 뼈대라는 점이었습니다.
정리하고 보니 좋아진 점은 분명했습니다.
로그인 상태에 따라 진입 흐름이 더 자연스러워졌고
결제 이후 지급 처리까지 이어지는 구조가 명확해졌습니다
이번 작업은 새로운 기능을 많이 추가했다기보다, 서비스가 더 믿을 만하게 동작하도록 바닥을 다진 작업에 가까웠습니다.
앞으로는 결제 실패/취소 처리 관리 같은 부분도 더 보완해보고 싶습니다.