페북 Graph API 자주 끊기는 시대, ASP.NET Core 로그인은 이렇게 관리해야 한다

ASP.NET Core에서 페북 로그인 붙이는 건 원래 진짜 쉽다. NuGet에서 Microsoft.AspNetCore.Authentication.Facebook 패키지 하나 설치하고 services.AddFacebook()만 해주면 끝이다. AppId랑 Secret 넣어주면 바로 로그인 화면 뜨고, 토큰까지 잘 들어온다.

근데 이걸 그대로 믿고 쓰다가는 어느 날 갑자기 서비스가 멈춘다. 나도 실제로 몇 년 전에 크게 당했다. 이유는 단순했다. NuGet 패키지 기본값이 바라보는 Facebook Graph API 버전이 너무 구식이었던 거다. 당시엔 v11을 쓰고 있었는데, 이게 페북에서 지원 종료되자 로그인 기능이 바로 깨져버렸다.

왜 이렇게 신경을 쓰는가

우리 POCU 아카데미소셜 로그인에만 의존한다. 우리 쪽에서 패스워드나 주민번호 같은 불필요한 고객 정보를 아예 저장하지 않는다. "패스워드 저장"이란 건 생각보다 굉장히 위험한 짓이다. 아무리 잘 암호화하고 잘 보관한다고 해도 유출 위험은 늘 존재한다. 실제로 보안 사고 뉴스를 보면 대부분은 "우리 서비스 DB가 털렸다 → 유저 비밀번호가 유출됐다" 패턴이니까.

우리는 그냥 인증은 전부 페북, 구글, 네이버 같은 외부 서비스에 맡기고, 거기서 인증된 결과만 받아온다. 우리 쪽은 사실상 "저 사람은 진짜 그 계정이 맞다"는 보증서만 받는 셈이다.

구체적으로 말하면, 페북 로그인 성공 후에 우리한테 떨어지는 건 대략 이런 값들이다.

  • Provider key: 페북이 발급해주는 유저 고유 키
  • Access token: 페북 Graph API에 접근할 수 있는 토큰
  • (옵션) 이메일, 이름 같은 기본 공개 정보

이 정도만 있으면 우리 서비스에서는 "아, 이 사람이 진짜 동일인"이라는 걸 확인할 수 있다. 우리 입장에선 훨씬 안전하다. "유저의 민감한 비밀번호"는 건드릴 필요도 없고, 책임도 외부 서비스가 대신 져준다.

잠깐, OAuth는 어떻게 동작할까?

사실 페북 로그인은 내부적으로 OAuth 2.0 프로토콜을 쓴다. 복잡하게 보면 끝도 없지만 아주 간단히 줄이면 이렇다.

  1. 사용자가 "페북으로 로그인" 버튼을 누른다.
  2. 우리 서비스는 사용자를 페북 로그인 페이지로 리디렉트한다.
  3. 사용자가 페북 계정/비밀번호로 로그인하고 동의 버튼을 누른다.
  4. 페북이 우리 서비스로 Authorization Code를 준다.
  5. 우리 서비스는 이 코드를 다시 페북에 보내서 Access Token을 받아온다.
  6. 그 토큰으로 /me API를 호출해서 유저 정보를 가져온다.

여기서 핵심은 우리 서비스가 직접 사용자 비밀번호를 알 필요가 전혀 없다는 것이다. 전부 페북이 인증해주고, 우리는 "페북이 보증한 토큰"만 신뢰하면 된다.

문제의 NuGet 패키지

그런데 문제는 이 과정에서 쓰이는 페북 Graph API 버전이 항상 최신은 아니라는 거다. 마소 쪽 Microsoft.AspNetCore.Authentication.Facebook 패키지는 기본적으로 내부 엔드포인트를 하드코딩해둔다. 예를 들어 예전에는 v11을 기본으로 쓰고 있었고, 이게 EOL되면서 서비스가 한순간에 깨져버렸다.

그래서 나는 그냥 이렇게 코드에서 직접 오버라이드한다.

services.AddAuthentication()
    .AddFacebook(facebookOptions =>
    {
        facebookOptions.AuthorizationEndpoint = Constants.AUTHORIZATION_ENDPOINT;
        facebookOptions.UserInformationEndpoint = Constants.USER_INFORMATION_ENDPOINT;
        facebookOptions.TokenEndpoint = Constants.TOKEN_ENDPOINT;

        facebookOptions.AppId = config["Authentication:Facebook:AppId"];
        facebookOptions.AppSecret = config["Authentication:Facebook:AppSecret"];
        facebookOptions.AccessDeniedPath = accountAccessDeniedPath;
        facebookOptions.Events.OnRemoteFailure = handleOnRemoteFailureAsync;
    });

그리고 상수는 이렇게:

public static class Constants
{
    public const string AUTHORIZATION_ENDPOINT = "https://www.facebook.com/v17.0/dialog/oauth";

    public const string USER_INFORMATION_ENDPOINT = "https://graph.facebook.com/v17.0/me";

    public const string TOKEN_ENDPOINT = "https://graph.facebook.com/v17.0/oauth/access_token";
}

왜 안 빼고 유지하냐?

사실 언제든 저 상수랑 오버라이드 코드를 빼고 싶었다. NuGet 패키지가 제때 최신 버전을 반영해주면 굳이 내가 관리할 필요가 없으니까. 그런데 현실은… v17이 곧 만료되는 지금까지도 정식 NuGet 패키지에는 반영이 안 돼 있다. preview 브랜치에는 이미 새로운 버전이 들어가 있는데도 정식 릴리스는 여전히 구버전을 쓰고 있다는 거다.

그러니 신뢰가 안 간다. 이쯤 되면 그냥 내가 직접 관리하는 게 속 편하다. 다행히 페북은 API 만료 전에 미리 이메일을 보내준다. 그때 알림을 받으면 코드에서 버전 문자열만 올려주고 테스트 돌리면 끝이다. 사실상 "내 손으로 버전 관리하는 구조"지만, 그래도 서비스가 한밤중에 갑자기 터지는 일은 피할 수 있다.

결론

페북은 너무 자주 구버전을 끊고, 마소 NuGet 패키지는 업데이트 속도가 그걸 못 따라간다. 그 사이에서 삽질하고 욕 먹는 건 결국 개발자다. 그래서 난 그냥 지금처럼 엔드포인트를 직접 오버라이드하고, 버전을 내가 관리하는 방식으로 계속 갈 거다.

교훈: ASP.NET Core에서 페북 로그인? 기본값 믿지 마라. 버전은 내가 직접 잡고 간다.

img

제대로 대우받는 개발자 | 부족한 컴공지식 배우기 | MIT급 컴공인강

최저임금으로 고통받는 일회성 프로그래머는 그만! POCU 아카데미가 올해 연봉협상을 책임지겠습니다!