Supabase Authentication을 사용해서 회원가입을 구현하는데, auth.users 테이블 외에 추가 사용자 정보(이름, 대학교, 구독 정보 등)를 별도 테이블에 저장하고 싶었습니다.
profiles 테이블에 저장// 1. Supabase Auth로 회원가입
const { data, error } = await supabase.auth.signUp({
email: fullEmail,
password: password,
});
// 2. profiles 테이블에 추가 정보 저장
const { error: profileError } = await supabase
.from("profiles")
.update({ name, university })
.eq("id", data.user.id);
트리거: auth.users에 유저 생성 시 자동으로 profiles 레코드 생성
create function public.handle_new_user()
returns trigger as $$
begin
insert into public.profiles (id, email)
values (new.id, new.email);
return new;
end;
$$ language plpgsql security definer;
create trigger on_auth_user_created
after insert on auth.users
for each row execute procedure public.handle_new_user();
// Console 출력
=== profiles 테이블 업데이트 결과 ===
Profile Data: [] // 빈 배열!
Profile Error: null
업데이트 할 레코드가 없다는 의미였습니다.
에러도 없는데 profile 테이블의 칼럼에 name, university의 값이 들어가질 않습니다.
새로운 레코드가 생기기도 전에, 클라이언트에서 너무 빨리 update를 시도하는 것 아닐까? 라는 생각이 들었습니다.
// 트리거가 레코드 생성할 때까지 대기
await new Promise(resolve => setTimeout(resolve, 1000));
const { data: profileData, error: profileError } = await supabase
.from("profiles")
.update(updateData)
.eq("id", data.user.id);
1초의 대기 시간을 줘서 레코드 생성 시간을 기다려보기로 했습니다.
Profile Data: [] // 여전히 빈 배열
const { data: { session } } = await supabase.auth.getSession();
console.log("Session:", session); // null!
세션(Session)이란?
auth.uid()가 사용자 ID를 반환왜 세션이 null인가?
Supabase에서 이메일 인증이 활성화되어 있으면:
1. 회원가입 → 이메일 발송
2. 사용자가 이메일 링크 클릭 → 계정 인증
3. 인증 완료 후에야 세션 생성
따라서:
auth.uid() = nullusing (auth.uid() = id) 통과 못함트리거는 정상 작동했지만, update가 RLS 정책 때문에 실패한 것!
이메일 인증은 꼭 필요한 기능이였기 때문에, 이메일 인증을 유지하면서 세션 없이도 정보를 저장하려면, 트리거에서 모든 정보를 한 번에 저장해야 한다.
1. 회원가입 시 메타데이터에 정보 포함
const { data, error } = await supabase.auth.signUp({
email: fullEmail,
password: formData.password.trim(),
options: {
data: {
name: formData.name.trim(),
university: formData.university,
},
},
});
if (data.user) {
// 트리거가 자동으로 처리하므로 별도 update 불필요!
setSignupSuccess(true);
}
2. 트리거 함수 수정 (메타데이터에서 정보 추출)
create or replace function public.handle_new_user()
returns trigger as $$
begin
insert into public.profiles (id, email, name, university)
values (
new.id,
new.email,
new.raw_user_meta_data->>'name',
new.raw_user_meta_data->>'university'
);
return new;
end;
$$ language plpgsql security definer;
options.data에 name, university 저장 → auth.users의 raw_user_meta_data에 저장됨