Apple Sign-In / Google Sign-In 연동 후 클라이언트에서는 500 에러만 보이는데, 서버 로그를 보면 실제 원인이 다른 경우가 있다. 오늘 마주친 케이스를 정리한다.

SSO 연동 초기에는 클라이언트(Flutter) 쪽 설정 문제인지, 서버 쪽 문제인지 구분하기가 쉽지 않다. 이 글에서는 서버 DB 컬럼명 불일치로 인한 PG::UndefinedColumn 에러를 빠르게 진단하고 수정하는 방법을 다룬다.


에러

PG::UndefinedColumn: ERROR: column users.uid does not exist
LINE 1: SELECT "users".* FROM "users" WHERE "users"."uid" = $1 ...

클라이언트(Flutter)에서는 401 Unauthorized로 보인다.


원인

OAuth 사용자를 찾는 컨트롤러 코드에서 uid 컬럼을 참조했지만, 실제 DB 스키마에는 uid 컬럼이 없고 provider_uid라는 이름으로 정의되어 있었다.

# 잘못된 코드
user = User.find_by(provider: provider, uid: uid)
user.uid = uid
# 올바른 코드
user = User.find_by(provider: provider, provider_uid: uid)
user.provider_uid = uid

왜 이런 실수가 생기나

OAuth를 처음 설계할 때 Devise 스타일의 uid를 떠올려 컬럼명을 결정하기 전에 코드를 먼저 작성하는 경우가 있다.

또는 다른 프로젝트에서 코드를 복사해올 때 해당 프로젝트의 컬럼명(uid)이 현재 프로젝트(provider_uid)와 달라서 그대로 붙여넣으면 이 문제가 생긴다.


확인 방법

1. schema.rb에서 컬럼명 확인

# db/schema.rb
create_table "users", force: :cascade do |t|
  t.string "provider"
  t.string "provider_uid"   # uid가 아님
  # ...
end

2. 직접 쿼리 확인

bundle exec rails c
User.column_names.grep(/uid|provider/)
# => ["provider", "provider_uid"]

수정

find_by와 속성 할당 모두 실제 컬럼명으로 맞춰준다.

def create_or_update_oauth_user!(provider:, uid:, email:, name:, avatar_url:)
  user = User.find_by(provider: provider, provider_uid: uid) ||
         User.find_by(email: email.downcase)
  user ||= User.new

  user.provider     = provider
  user.provider_uid = uid      # uid → provider_uid
  user.email        = email.downcase
  # ...
  user.save!
  user
end

교훈

클라이언트 쪽에서 SSO 에러가 나면 반사적으로 클라이언트(토큰, 설정 파일)를 의심하게 된다. 그런데 서버 로그를 먼저 보면 PG::UndefinedColumn 같은 DB 에러가 바로 찍혀 있는 경우가 많다.

소셜 로그인 실패 시 클라이언트 로그보다 서버 로그를 먼저 확인하는 게 빠르다.


유사한 컬럼 불일치 패턴

같은 유형의 실수가 다른 컬럼에서도 발생할 수 있다.

잘못된 컬럼명실제 컬럼명상황
uidprovider_uidOAuth 사용자 식별자
namedisplay_name사용자 표시 이름
imageavatar_url프로필 이미지
tokenaccess_tokenOAuth 액세스 토큰

다른 프로젝트에서 코드를 복사해올 때 컬럼명이 다른지 반드시 확인한다.


Rails에서 컬럼명 빠르게 확인하는 방법

# 콘솔에서 확인
bundle exec rails c
User.column_names
# => ["id", "email", "provider", "provider_uid", "display_name", ...]

# schema.rb 직접 확인
grep -A 20 'create_table "users"' db/schema.rb

예방책: 컨트롤러 작성 전 schema.rb 먼저 확인

OAuth 컨트롤러를 작성하기 전에 db/schema.rb에서 실제 컬럼명을 먼저 확인하는 습관을 들이면 이런 실수를 줄일 수 있다.

또는 모델에 명시적으로 alias를 정의해두면 유연하게 대응할 수 있다.

# app/models/user.rb
alias_attribute :uid, :provider_uid

단, alias를 남용하면 오히려 혼란을 줄 수 있으므로 신중하게 사용한다.