소셜 로그인 화면에서 사용자가 권한 제공을 거부하면 SDK 콜백은 성공 토큰 대신 오류를 반환했다. 앱은 이를 일반 로그인 실패로 보여주고 자동 재시도해 같은 권한 화면을 다시 열었다. 사용자의 선택을 장애처럼 처리한 셈이었다.
권한 거부, 사용자의 취소, 네트워크 실패, 잘못된 설정은 모두 다음 행동이 달랐다.
공급자 오류를 앱 상태로 변환했다
SDK별 오류 문자열을 화면에서 직접 비교하지 않고 인증 계층에서 의미 있는 결과로 바꿨다.
public abstract record SocialLoginResult
{
public record Success(string Proof) : SocialLoginResult;
public record Cancelled : SocialLoginResult;
public record PermissionDenied : SocialLoginResult;
public record TemporaryFailure : SocialLoginResult;
public record ConfigurationError : SocialLoginResult;
}
토큰과 공급자 원문 응답은 로그나 화면 상태에 남기지 않았다.
거부 뒤에는 자동 재시도하지 않았다
사용자가 명시적으로 거부한 조건은 시간이 지나도 저절로 바뀌지 않는다. 로그인 선택 화면으로 돌아가 다른 방법을 고르거나, 필요한 권한과 사용 목적을 확인한 뒤 사용자가 다시 시작하게 했다.
일시적 네트워크 실패만 제한적인 재시도 대상으로 두고 설정 오류는 개발·운영 확인이 필요한 상태로 분리했다.
최소 권한과 기능 저하를 생각했다
로그인에 꼭 필요하지 않은 추가 권한은 첫 인증에서 요구하지 않고 해당 기능을 사용할 때 요청하는 방식을 검토했다. 선택 권한을 거부해도 기본 로그인은 가능하도록 공급자 계약과 서버 처리를 맞췄다.
권한 안내 문구는 왜 필요한지 설명하되 동의를 강요하거나 거부 버튼을 숨기지 않았다.
서버도 선택 권한이 비어 있는 요청을 정상적인 계약으로 처리해야 했다. 클라이언트에서만 기본값을 넣으면 다른 플랫폼과 동작이 달라질 수 있어 API 응답과 계정 연결 상태를 함께 확인했다.
사용자 선택도 테스트 시나리오였다
개발할 때 성공 콜백만 반복하면 거부 흐름은 뒤늦게 발견된다. 첫 동의 거부, 이전 동의 철회, 일부 권한만 허용, 브라우저에서 취소, 앱 복귀를 확인했다.
이 경험 뒤 외부 인증의 오류 코드를 성공하지 못한 한 덩어리로 보지 않는다. 사용자가 선택한 결과와 시스템 실패를 구분해야 안전하고 예측 가능한 로그인 경험이 됐다.