개요

사내 프로젝트에 구현된 기존의 OAuth 인증 절차를 더 유연하게 개선한 경험을 공유하려고 합니다. 이미 많은 분들이 알고 계시는 표준일 수도 있습니다.

문제 상황

프로젝트의 기존 OAuth 인증 절차는 다음과 같습니다.

OAuth 연동 방법으로 널리 알려진 보편적인 방식이며, 학부에서 팀 프로젝트를 할 때에도 동일하게 구현을 해왔기 때문에 익숙한 느낌입니다.

그런데 몇가지 사소한 단점이 있습니다.

  • 클라이언트에서 불필요하게 많은 정보를 다루어야 함
    • 로그인 링크 생성을 위해 Provider에 등록된 Client ID, Scope, Redirect URI 등 사용함
    • 서버와 매번 동일하게 환경 설정을 해주어야 하는 부분이며, 특히 개발 과정에서 Redirect URI가 변경될 때 마다 고역임
  • 클라이언트에서 Authorization Code를 받았다가 그대로 다시 서버에 전달해야 함
    • 사소하지만 어쨌든 통신 비용임
    • 6번~11번 과정에 대한 로딩 화면을 직접 구현해야 함

소규모 프로젝트에서는 쉽게 넘어갈 문제이지만, 개선 가능성이 보여지는 것은 사실입니다.

개선 방안

아래는 개선된 인증 절차입니다.

로그인 버튼을 누른 이후의 모든 작업은 백엔드에서 정해집니다. 따라서 프론트엔드 개발자는 OAuth 연동에 크게 힘쓸 필요가 없어졌습니다.

상세 절차

  1. 로그인 버튼 클릭 사용자가 소셜 로그인 버튼을 클릭합니다.
  2. GET /auth/{provider} 클라이언트가 서버의 auth API를 호출합니다. provider 경로는 Provider의 이름입니다.
  3. Provider로 리다이렉트 서버에서 가지고 있는 Client ID, Scope, Redirect URI 등을 이용하여 OAuth 로그인 링크를 생성하고 클라이언트에 302 응답으로 보냅니다.
  4. 인증 요청 클라이언트가 302 응답으로 받은 OAuth 로그인 링크로 리다이렉트 됩니다.
  5. 로그인 페이지 사용자에게 OAuth 로그인 페이지가 보여집니다.
  6. 로그인 및 권한 승인 사용자가 로그인을 수행합니다.
  7. 백엔드 API로 리다이렉트 설정된 Redirect URI에 따라 Provider가 Authorization Code와 함께 백엔드 API로 리다이렉트 시킵니다.
  8. 토큰 요청 백엔드에서 Provider를 호출하여 Authorization Code를 사용하여 OAuth Token을 발급받습니다.
  9. 토큰 수신 백엔드가 Provider로 부터 필요한 토큰을 전달받습니다.
  10. 사용자 정보 요청 백엔드에서 OAuth Token을 사용하여 Provider에게 해당 사용자 정보를 요청합니다.
  11. 사용자 정보 수신 백엔드가 Provider로 부터 사용자 정보를 전달받아 필요한 작업을 수행합니다.
  12. 자체 토큰 발급 서비스에서 사용할 수 있는 JWT Token을 발급하여 쿠키에 담아 클라이언트의 로그인 성공 페이지로 리다이렉트 응답을 보냅니다.

    클라이언트가 네이티브 앱인 경우 브라우저 쿠키를 사용할 수 없기 때문에, 이 단계를 구현할 수 없습니다. 대신 TTL이 짧은 일회성 코드나 티켓을 발급하여 응답하고, 클라이언트가 다시 이를 이용하여 JWT Token을 요청하는 식으로 구현할 수 있습니다.

  13. 로그인 성공 로그인을 위한 모든 절차가 수행되었으며 클라이언트는 발급 받은 JWT Token으로 서비스를 이용할 수 있습니다.

개선 결과

  • 클라이언트는 OAuth 인증 절차를 신경쓰지 않아도 됩니다.
    • 로그인 API만 호출한다면 이후의 과정은 Provider와 백엔드가 리다이렉트로 알아서 진행해줍니다.
    • Client ID나 Secret, Scope, Redirect URI 등 환경 설정은 오직 백엔드에서 단독으로 관리하게 됩니다.
  • 로그인 링크 생성 이후 별도의 로딩 화면을 구현하지 않아도 됩니다.
    • Provider의 로그인 화면으로 리다이렉트 된 후 부터 로그인 성공 화면으로(혹은 대시보드로) 돌아올 때 까지 오로지 Provider의 페이지만 보여지게 됩니다.
    • 가장 부담이 되는 백엔드-Provider 토큰 교환 및 발급 과정에서도 여전히 Provider의 로딩 화면에 머무르게 됩니다.

예제 코드

구현 방법에 정답은 없습니다. 아래는 Claude Code로 작성한 React + Express 데모입니다.

https://github.com/tkddnr1022/oauth-strategy

보안 대책

기존 절차와 개선된 절차 모두 여전히 리다이렉트 과정에서 CSRF 공격이나 Authorization Code 탈취가 발생할 수 있습니다. 본 글의 주제는 토큰 발급 과정을 백엔드에서 주도함으로써 OAuth 인증 절차를 더 유연하게 만드는 것에 초점을 두었기 때문에, 이러한 내용은 포함하지 않았습니다.

보안 위협까지 고려한 Best Practice에 대해서는 아래 자료를 참고하면 좋을 것 같습니다.

https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10