본인인증 DI 중복 계정을 탐지하는 API를 만든 이유

김민석·2025년 10월 10일
0

Tech Deep Dive

목록 보기
31/58

Intro

저는 본인인증 DI가 같은 계정이 여러 개 생기는 문제를 겪었습니다. 사용자에게 “이미 인증한 계정이 있어요”라고 안내하고 싶었지만, RLS 때문에 클라이언트가 마음대로 프로필을 조회할 수 없었죠. 그래서 서비스 롤 클라이언트를 이용해 중복 계정을 탐지하는 API를 만들었습니다.

핵심 아이디어 요약

  • DI 값을 파라미터로 받아 동일한 프로필을 모두 조회합니다.
  • 세션 사용자가 있으면 본인을 제외한 계정만 반환합니다.
  • Supabase Auth의 사용자 정보까지 결합해 어떤 계정이 활성 상태인지 표시합니다.

준비와 선택

  1. 서비스 롤: 프로필과 Auth 정보를 함께 조회해야 해서 서비스 롤 클라이언트를 사용했습니다.
  2. 현재 사용자 구분: 세션에서 user ID를 읽어 같은 DI라도 현재 로그인한 계정은 제외했습니다.
  3. fallback: DI 파라미터가 없으면 현재 사용자 프로필에서 DI를 가져와 조회했습니다.

구현 여정

Step 1: DI 결정

쿼리에 di가 없으면 세션 사용자 프로필을 조회해 DI를 찾습니다. 둘 다 없으면 400으로 종료합니다.

Step 2: 프로필 조회

프로필 테이블에서 동일한 DI를 가진 항목을 모두 가져옵니다. 필요한 필드는 이름, 전화번호, 인증 여부 등입니다.

Step 3: Auth 사용자 매칭

각 프로필 ID로 admin.auth.admin.getUserById를 호출해 활성/비활성 상태를 확인합니다. 현재 사용자와 동일하면 otherUsers에서 제외합니다.

import { createAdminClient } from './supabaseAdmin';

const adminClient = createAdminClient();

const { data: profiles } = await adminClient
  .from('profile')
  .select('id, di, full_name, phone_number, is_verified, is_complete')
  .eq('di', di);

const users = await Promise.all(
  (profiles ?? []).map(async profile => {
    const { data } = await adminClient.auth.admin.getUserById(profile.id);
    return data?.user ?? null;
  }),
);

const otherUsers = users.filter(
  user => user && (!currentUserId || user.id !== currentUserId),
);
return {
  success: true,
  di,
  profiles,
  users,
  otherUsers,
  isDuplicated: otherUsers.length > 0,
};

겪은 이슈와 해결 과정

  • 권한 문제: 서비스 롤이 아니면 프로필과 Auth를 동시에 볼 수 없어, 관리자 클라이언트 사용을 강제했습니다.
  • Auth 호출 실패: 일부 계정은 삭제되어 있어 조회가 실패했습니다. try/catch로 예외를 무시하고 null을 반환해 흐름을 유지했습니다.
  • 응답 형식: 프런트에서 활용하기 쉽도록 isDuplicated 플래그와 otherUsers 배열을 포함해 반환했습니다.

결과와 회고

이제는 DI가 중복된 사용자가 있으면 UI에서 즉시 알려줄 수 있습니다. 계정 복구나 고객센터 응대도 훨씬 빨라졌죠. 다음에는 중복 계정을 자동으로 잠그는 정책을 검토해볼 생각입니다.

여러분은 본인인증 식별자를 어떻게 관리하고 계신가요? 다른 사례가 있다면 댓글로 공유해주세요.

Reference

profile
동업자와 함께 창업 3년차입니다. Nextjs 위주의 프로젝트를 주로 하며, React Native, Supabase, Nestjs를 주로 사용합니다. 인공지능 야간 대학원을 다니고 있습니다.

0개의 댓글