화이트라벨 앱에 소셜 로그인을 붙일 때 본앱 SDK를 그대로 못 쓰는 이유
화이트라벨 앱에 본앱 소셜 로그인 SDK를 그대로 붙이면 로그인은 되지만, 소셜 ID가 앱마다 다르게 발급돼 서버가 계정을 엉뚱하게 매핑합니다. 인증수단과 앱 출처를 별도 축으로 분리해야 합니다.
본앱에 이미 소셜 로그인이 붙어 있습니다. 같은 코드베이스에서 파생시킨 화이트라벨 앱에도 소셜 로그인을 넣어달라는 요청이 왔습니다.
"SDK는 이미 들어 있으니 버튼만 붙이면 되는 거 아닌가?"
절반은 맞습니다. 같은 코드베이스에서 빌드 변형으로 파생시킨 앱이라면 SDK 의존성도, 초기화 코드도, 로그인 호출부도 이미 들어 있습니다. 다시 깔 것은 없습니다.
문제는 SDK가 혼자서는 동작하지 않는다는 데 있습니다. SDK는 앱 식별자와 플랫폼 콘솔 등록에 묶여 있고, 그 두 가지가 파생 앱에서 전부 갈립니다. 그리고 서버 쪽에는 아무도 예상하지 않는 지뢰가 하나 더 있습니다.
세 가지를 나눠 봅시다.
1. 소셜 플랫폼의 사용자 ID는 "앱 단위 스코프"다
대부분의 소셜 플랫폼에서 사용자 식별자는 전역 고유값이 아니라 앱(서비스)별로 발급됩니다. 같은 사람이 같은 소셜 계정으로 로그인해도 앱이 다르면 다른 번호가 나옵니다.
화이트라벨에서는 파생 앱이 다른 조직 소유의 소셜 앱을 쓰는 경우가 흔합니다. 파트너사가 자기 이름으로 개발자 콘솔에 앱을 등록해두는 것입니다. 이때 본앱 키를 그대로 재사용하면 어떻게 될까요?
로그인은 됩니다. 그게 함정입니다.
토큰도 정상으로 떨어지고 사용자 정보도 잘 내려옵니다. 문제는 그 식별자를 파트너 서버로 넘겨 회원을 매핑하는 순간 터집니다. 파트너의 웹 서비스는 자기 앱 기준 식별자를 갖고 있는데, 우리 앱이 보낸 건 본앱 기준 식별자입니다. 같은 사람인데 값이 다르니 "가입된 적 없는 사용자"가 됩니다.
통합 테스트 단계에서, 그것도 파트너 쪽 데이터가 붙고 나서야 발견되는 유형의 버그입니다.
2. SDK 설정은 앱 식별자에 묶여 있다
SDK 초기화 키, OAuth 복귀용 URL 스킴, 번들 ID, 패키지명, 키해시 — 전부 앱 식별자에 종속됩니다. 바이너리가 갈리는 순간 전부 새로 등록해야 합니다.
<!-- 복귀 스킴부터 앱 키에 종속된다 -->
<activity android:name=".auth.AuthCodeHandlerActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- {NATIVE_APP_KEY} 가 파생 앱에서는 다른 값이 된다 -->
<data android:scheme="socialsdk${NATIVE_APP_KEY}" android:host="oauth" />
</intent-filter>
</activity>특히 Android 키해시는 3종이 필요합니다.
| 키해시 | 언제 쓰이나 | 빠뜨리면 |
|---|---|---|
| 디버그 | 로컬 개발 빌드 | 개발 중 바로 발견 |
| 릴리스 | 자체 서명 APK | 사내 배포에서 발견 |
| 스토어 재서명분 | 스토어가 앱을 다시 서명한 배포본 | 스토어 버전만 로그인 실패 |
세 번째가 실무에서 가장 자주 터집니다. 스토어에 앱 서명을 위임하는 방식(Play App Signing 등)을 쓰면 업로드한 APK와 사용자가 내려받는 APK의 서명이 다릅니다. 개발 빌드에서는 멀쩡하고, QA 빌드에서도 멀쩡하고, 스토어에 올린 순간부터 로그인이 안 됩니다. 배포 직전에 발견되는 전형적인 유형입니다.
3. 서버가 "인증수단 코드" 하나로 계정 체계를 정한다면 — 지뢰
여기가 진짜 문제입니다. 레거시 서버에서 아주 흔한 패턴이 있습니다.
// 인증수단 코드만 보고 계정 prefix를 결정
if ("2".equals(input.getAuthType())) { // 2 = 소셜 A
userId = "social_a_" + input.getUserId();
} else if ("3".equals(input.getAuthType())) { // 3 = 소셜 B
userId = input.getUserId();
}authType 은 "어떤 수단으로 인증했나" 를 뜻합니다. 그런데 이 코드는 그 값 하나로 "어느 계정 체계에 속하나" 까지 결정해버립니다. 두 개의 서로 다른 질문에 답이 하나뿐인 것입니다.
본앱 하나만 있을 때는 아무 문제가 없습니다. 소셜 A로 로그인하면 소셜 A 계정이 맞으니까요. 파생 앱이 생기는 순간 전제가 깨집니다.
파생 앱이 본앱 로그인 코드를 그대로 재사용해서 같은 authType 으로 요청을 보내면, 서버는 그것이 어느 앱에서 온 요청인지 알 방법이 없습니다.
파생 앱 사용자가 본앱 계정을 갖게 됩니다. 그리고 이건 에러가 아니라 정상 응답입니다. 로그인은 성공하고, 세션도 발급되고, 앱은 아무 이상 없이 동작합니다. 계정이 엉뚱한 체계에 만들어졌다는 사실만 아무도 모릅니다.
해결: 축을 하나 더 만든다
인증수단과 앱 출처는 직교하는 두 축입니다. 그러니 파라미터도 두 개여야 합니다.
// Before — 한 축에 두 의미가 섞여 있다
String userId = resolvePrefix(input.getAuthType()) + input.getUserId();
// After — 인증수단과 앱 출처를 분리
String prefix = resolvePrefix(input.getAuthType(), input.getAppOrigin());
String userId = prefix + input.getUserId();private String resolvePrefix(String authType, String appOrigin) {
// 파생 앱은 소셜 로그인이어도 자체 계정 체계를 탄다
if (PARTNER_APP.equals(appOrigin)) {
return PARTNER_PREFIX;
}
return MAIN_APP_PREFIXES.get(authType);
}파생 앱의 인증 흐름은 결과적으로 이렇게 됩니다.
소셜 SDK 인증 → 소셜 식별자 획득
→ 파트너 인증서버로 전달 (여기서 회원 매핑)
→ 파트너 계정 ID 수신
→ 파생 앱 prefix 부착 → 세션 발급본앱은 소셜 식별자를 그대로 계정 ID로 쓰지만, 파생 앱은 소셜 식별자를 파트너 계정으로 교환한 뒤 씁니다. 같은 SDK를 쓰지만 그 뒤의 경로가 완전히 다릅니다.
정리
| 항목 | 재사용 가능? |
|---|---|
| SDK 통합 노하우 · 코드 구조 | 그대로 재사용 |
| 소셜 플랫폼 앱 키 / 콘솔 설정 | 소유자가 다르면 전부 새로 |
| 번들 ID · 패키지명 · 키해시 3종 | 앱이 갈리면 전부 새로 |
| 서버 계정 prefix 분기 | 축을 하나 더 만들어야 함 |
이 구분은 공수를 산정하거나 방어할 때도 그대로 쓸 수 있습니다.
"학습 비용은 넣지 않았습니다. 해본 일이니까요. 넣은 건 설정 비용인데, 앱도 다르고 소셜 앱도 달라서 설정은 재사용이 되지 않습니다."
세 가지 중 1번과 3번은 테스트에서 에러로 잡히지 않는다는 공통점이 있습니다. 로그인이 성공하기 때문입니다. 잘못된 값이 조용히 흘러가다가 한참 뒤 매핑 단계에서 드러납니다. 화이트라벨 파생 작업을 시작할 때 이 두 가지를 먼저 확인해두면 통합 단계에서 며칠을 아낍니다.