[OAuth] OAuth 2.0의 배경, 개념 및 인가 플로우

Daehwan Kim·2025년 12월 4일

OAuth

목록 보기
1/3
post-thumbnail

서론

현대오토에버 코딩 SW 스쿨에서 서버부터 클라이언트까지 전반적인 개발을 경험하면서 배운 것 중 하나가 있다. 바로 인증(Authentication)과 인가(Authorization)의 중요성이다. 대부분의 웹 및 모바일 어플리케이션은 로그인을 기반으로 동작하며, 사용자 정보를 안전하게 보호하고 권한을 제어하는 것이 필수이다.

프로젝트를 진행하면서 로그인 처리, 세션 유지, 토큰 관리, 소셜 로그인(Kakao OAuth) 등 인증 기능을 여러번 구현해야했다. 당시에 나는 OAuth라는게 있는지도 몰랐으며, 이러한 상태로 기능을 구현했으니 당연히 구조적 취약점을 고려하지 못한 채로 기능이 구현되었다. 프로젝트 발표 및 멘토링 과정에서 여러 취약점을 지적받고 이때 처음으로 OAuth라는게 있다는 것을 알게되었다.

이러한 과정을 통해서 인증 및 인가를 제대로 이해하여 구현해보고자하는 목표가 생겼고, 프로젝트 기간동안 RFC 6749 등의 공식 문서를 기반으로 OAuth 2.0에 대해 공부했다. 이 글에서는 그 과정에서 정리한 OAuth 2.0 Framework의 개념과 동작 방식을 공유하고자 한다.

추가로 최근 쿠팡에서 개인정보 유출 사고가 발생했는데, 해당 사고는 OAuth 자체의 취약점이라기보다는, 토큰 관리 및 검증 방식의 구현 상 문제와 연관된 사례로 보인다.


인증과 인가

OAuth 2.0을 이해하기 위해서는 먼저 인증(Authentication)과 인가(Authorization)의 개념을 먼저 명확히 구분해야한다.

인증(Authentication)이란

"이 사용자가 누구인가?"를 확인하는 과정을 의미한다. 즉, 시스템에 접근하려는 주체가 주장하는 신원이 사실인지를 검증하는 절차이다.

따라서 일반적으로 인증은 다음과 같은 정보들을 통해 수행이 된다.

  • 사용자가 알고있는 정보(ID/ Password)

  • 사용자가 가지고 있는 것(OTP, 인증 앱 등)

  • 사용자의 고유한 특성(안면 인식, 지문 인식)

    웹 어플리케이션 환경에서 일반적인 인증 과정은 로그인(login)이다. 간단히 말해서 사용자가 ID와 비밀번호를 입력하면, 서버는 이를 검증하고 해당 사용자가 누구인지 확인하는 것이다.

인가(Authorization)이란

인가는 일반적으로 인증 이후 수행되는 개념으로, "이 사용자가 무엇을 할 수 있는가?"를 검증하는 단계이다.
즉, 이미 인증된 사용자에게 어떤 리소스에, 어떤 범위까지 접근을 허용할 것인지를 판단하는 절차이다.

예시로 다음과 같은 상황이 있을 수 있다.

  • 동일한 서비스에 로그인한 사용자이어도
    • 일반 사용자는 게시글 조회만 가능하고,
    • 관리자는 게시글 삭제 및 사용자 관리가 가능할 수 있다.

이때 두 사용자는 모두 인증은 완료되었지만, 각각에게 부여된 권한(Authorization)이 서로 다르다.

이처럼 인증과 인가는 서로 다른 목적과 역할을 가지는 개념이다.

추가로, 엄밀히 말하면 OAuth 2.0은 로그인(Authentication)을 위한 표준이 아니라, 사용자의 리소스에 대한 접근 권한을 제3자 애플리케이션에 위임하기 위한 권한 위임(Authorization) 프레임워크이다.

실제 로그인 기능은 OAuth 위에서 동작하는 OpenID Connect(OIDC)를 통해 구현된다.


OAuth의 등장 배경

많은 애플리케이션이 등장하면서 각 서비스에서 다른 서비스를 연동하여 확장할 필요성이 생겼다. 또한, 로그인의 경우 각각의 서비스에서 하나의 사용자가 여러 ID를 생성하게 되는데 이러한 경우에도 밀접한 서비스 간에는 하나의 ID로 관리를 할 필요성이 생겼다.

이러한 요구사항을 해결하기 위해 OAuth라는 권한 위임 프레임워크가 등장하였고, 이후 이를 개선한 OAuth 2.0이 표준으로 자리잡게 되었다.

각 서비스들이 다른 서비스와 연동 시, 데이터를 다루는 방식, 특히 사용자의 자원에 제3자 애플리케이션이 접근해야하는 상황이 증가하면서, 기존 방식은 여러 문제점을 보였다. 이러한 문제를 해결하기 위해 등장한 것이 OAuth 2.0이다. OAuth 2.0의 목적은 다음과 같다.

  • OAuth 2.0 Framework의 목적
    • 제3자 애플리케이션이 HTTP 서비스에 대해 제한된 접근 권한을 얻을 수 있도록 한다.
    • 이는 리소스 소유자와 HTTP 서비스 간의 승인 절차(approval interaction)을 조율하여 리소스 소유자를 대신해서 접근 권한을 부여 받도록 하거나,
    • 제3자 애플리케이션이 자체적으로(access on its own behalf) 접근 권한을 획득할 수 있도록 허용함으로써 이루어진다.

다음으로는 OAuth 2.0 Framework에서 제안하는 역할을 기반으로 기존의 문제점을 다루고, OAuth에서는 이를 어떻게 극복했는지를 다루고자 한다.


OAuth 2.0: Role

먼저 OAuth 2.0에서의 정의하고 있는 역할이다. OAuth에서는 4가지 역할을 정의하고 있다.


1. 리소스 소유자(resource owner)

보호된 리소스에 접근을 허가할 수 있는 주체(entity)로 리소스 소유자가 사람인 경우, 이를 엔드 유저(end-user)라고 부른다.

즉, 사용자라고 생각하면 된다.


2. 리소스 서버(resource server)

보호된 리소스를 호스팅하며, 액세스 토큰을 사용하여 보호된 리소스에 대한 요청을 받아드이고 응답할 수 있는 서버이다.

즉, 사용자의 리소스를 가지고 있는 서버이다.


3. 클라이언트(client)

리소스 소유자의 승인을 얻어, 리소스 소유자를 대신하여 보호된 리소스 요청을 수행하는 애플리케이션.

즉, 사용자에게 동의를 얻어 액세스 토큰으로 사용자의 자원을 요청하는 주체이다.


4. 인가 서버(Authorization server)

리소스 소유자를 인증하고, 권한(Authorization)을 획득한 후 클라이언트에게 액세스 토큰을 발급하는 서버

즉, 사용자 인증과 동의 절차를 수행하고, 그 결과로 클라이언트에게 액세스 토큰을 발급하는 서버


추가 설명

인가 서버와 리소스 서버 간의 상호작용은 이 OAuth 2.0 Framework의 사양의 범위를 벗어난다. 즉, 인가 서버와 리소스 서버는 동일한 서버일 수도 있고 별개의 서버일 수도 있다. 또한, 하나의 인가 서버가 여러 리소스 서버에서 받아들여지는 액세스 토큰을 발급할 수도 있다.

이는 이후 구현 시, 설명을 위해 RFC 6749의 전문을 가져온 내용이다.


제 3자 애플리케이션의 사용자의 리소스 접근 시 문제

위 4가지 역할을 기반으로 우리가 왜 OAuth가 필요했는지에 대한 배경을 이해해보고자 한다. 먼저, OAuth 2.0 Framework가 없는 상황에서 제 3자 애플리케이션이 사용자의 리소스를 요청하는 상황을 가정해보자.

  • 제 3자 애플리케이션: 통합 캘린더 서비스
  • 사용자의 리소스: Google Calendar의 저장되어 있는 사용자(나)의 일정 데이터

이 가정은 위 OAuth의 역할에 다음과 같이 매칭된다.

예시OAuth 역할설명
사용자(본인)리소스 소유자(resource owner)자신의 일정 데이터에 대한 접근을 허가할 수 있는 리소스 소유자
Google Calendar리소스 서버(resource server)일정 데이터를 저장하고 호스팅하는 서버
구글 로그인 창(OAuth 서버)인가 서버(authorization server)지금 섹션에는 직접적으로 나오지는 않지만 실제 역할 상 존재한다.
통합 캘린서 서비스클라이언트사용자를 대신하여 캘린더 API 접근을 요청하는 제 3자 앱

위 상황에서 제 3자 애플리케이션이 사용자의 리소스인 일정 데이터를 접근하기 위해 가장 간단한 방법은 사용자의 id와 비밀번호를 사용하여 Google Calendar에 로그인 하는 것이다.

위 상황에서 제 3자 애플리케이션이 일정 데이터를 가져오게 된다면 발생하는 문제점은 대표적으로 3가지이다.

  • 사용자는 신뢰할 수 없는 어플리케이션에 자신의 민감 정보를 제공해야한다.
  • 통합 캘린더 애플리케이션은 사용자 자격 증명(ID/Password)을 직접 입력하여 로그인 요청을 시도해야한다.
  • 구글은 신뢰할 수 없는 제 3자 애플리케이션이 임의의 사용자를 대신하여 로그인을 시도하는 것을 허용해야한다.

추가적으로, 제3자 애플리케이션은 사용자의 전체 계정에 대한 과도한 접근 권한을 갖게 되며, 사용자는 특정 애플리케이션만 선택적으로 접근을 철회할 방법이 없는 등의 문제가 존재한다.


OAuth 2.0 Framework의 제안

앞서 살펴본 문제들을 해결하기 위해서 OAuth 2.0 Framework는 인가 레이어를 도입하고, 사용자 비밀번호를 직접 공유하지 않고도 제3자 애플리케이션이 보호된 리소스에 접근할 수 있는 방식으로 토큰 기반 접근을 제안했다.

OAuth의 인가 레이어의 설명을 위해, 먼저 토큰에 대해서 알아보자.

토큰(Token)

토큰은 권한이나 신분을 나타내는 증표로 인증키, 출입증이라고 생각하면 된다.

토큰 방식을 사용하면 다음 문제를 해결할 수 있다.

  • 비밀번호 공유 없이도 권한 위임 가능
  • 특정 앱에 부여된 권한만 선택적으로 회수 가능
  • 계정 전체가 아니라 필요한 권한만 제한적으로 제공 가능
  • 짧은 수명의 토큰을 사용하여 보안을 강화할 수 있음.

OAuth의 핵심은 access token이며, refresh token은 장기 세션 유지를 위해 선택적으로 발급될 수 있다.

다만, 토큰의 형식은 OAuth 2.0 표준에서 정의하지는 않는데, JWT(Json Web Token)은 실무에서 보편적으로 사용되는 구현 방식 중 하나이다.

1. 액세스 토큰(Access Token)

액세스 토큰은 제3자 애플리케이션인 클라이언트가 리소스 서버(API)에 특정 요청을 보낼 수 있도록 인가 서버가 발급하는 권한 증명서이다. 즉, "이 앱이 사용자의 허락을 받아서 이 API를 호출할 수 있습니다."를 증명하는 토큰이다.

액세스 토큰이 JWT 형식으로 발급되는 경우, PAYLOAD에는 토큰의 의미를 나타내는 클레임이 포함될 수 있다.

예를 들어 다음과 같은 정보가 들어갈 수 있다.

  • scope: 허용된 권한 범위
  • iss: 토큰 발급자(issuer)
  • aud: 토큰 대상(resource server 또는 intended audience)
  • exp: 토큰 만료 시각
  • iat: 토큰 발급 시각
  • 필요에 따라 sub, client_id, jti 등의 추가 클레임

2. 리프레시 토큰(Refresh Token)

리프레시 토큰은 단순하다. 리프레시 토큰은 말 그래도 액세스 토큰을 갱신(리프레시)를 하기 위해 존재하는 토큰이다.

액세스 토큰이 만료되면 클라이언트는 리프레시 토큰을 사용해서 다시 액세스 토큰을 발급 받으며, 클라이언트는 리프레시 토큰을 이용하여 보안과 편의성을 모두 달성할 수 있다.

OAuth 2.0 Framework 적용

OAuth 2.0 Framework에서는 인가를 부여받는 절차를 그랜트(Grant)라고 부르며, 총 4가지의 방식이 존재한다.

  1. Authorization Code Grant(인가 코드 방식)
  2. Implicit Grant(암시적 방식)
  3. Resource Owner Password Credentials Grant(자원 소류자 비밀번호 자격 증명 방식)
  4. Client Credentials Grant(클라이언트 자격 증명 방식)

이 중 실제 서비스 환경에서 사용되는 방식은 인가 코드 방식이다.

다른 방식이 사용되지 않는 이유는 OAuth 공식 홈페이지의 Grant Type에서 확인할 수 있다.

OAuth 인가 코드 그랜트 방식

OAuth 2.0의 인가 코드 그랜트 방식은 사용자가 직접 인가 서버에서 로그인하고 동의를 마친 뒤, 그 결과로 발급된 인가 코드(Authorization Code)를 이용하여 클라이언트가 액세스 토큰과 리프레시 토큰을 발급 받는 방식으로 권한을 인가한다.

RFC 6749에서는 위와 같이 플로우가 설명이 되어 있으나, 이해를 위해 다시 아래와 같이 정리해보았다.

인가 코드 그랜트 방식이 표준이 된 이유

다른 방식들의 한계점만 간단히 설명하자면 다음과 같다.

  • Implicit Grant: 토큰 탈취 위험 발생
  • Resource Owner Password Credentials Grant: 사용자의 비밀번호를 제3자 애플리케이션에 노출
  • Client Credentials Grant: 서버-서버 간 통신을 위해 존재하는 방법이므로 사용자 개입에 적합하지 않음.

위 문제들을 인가 코드 그랜드 방식은 다음 이점으로 표준이 되었다.

  • 사용자 인증을 클라이언트가 아니라 인가 서버가 전담함.
    • 클라이언트가 사용자 비밀번호를 직접 다루지 않음.
  • 토큰이 바로 브라우저로 전달되지 않음.
    • Authorization Code Grant의 핵심은 access token이 authorization response에 직접 포함되지 않고, 이후 token endpoint 교환 단계에서 발급된다는 점이다.
    • 이 교환은 서버가 수행할 수도 있고, 브라우저 기반 클라이언트가 PKCE와 함께 수행할 수도 있다.
  • 필요한 경우 refresh token까지 함께 발급할 수 있어 장기 세션 관리에 활용할 수 있음.
    • 다만 refresh token 발급 여부는 authorization server 정책과 클라이언트 특성에 따라 달라진다.
  • PKCE(Proof Key for Code Exchange)와 결합하면 모바일 SPA 환경에서도 안전하게 사용할 수 있음.
  • OAuth 2.1과 최신 보안 권고에서는 사용자 참여형 웹•모바일 클라이언트의 기본 흐름으로 Authorization Code Grant + PKCE를 권장한다.
    • 반면, Implicit Grant와 Resource Owner Password Credentials Grant는 제외됨.
    • 다만 서버 간 통신과 같이 사용자가 직접 개입하지 않는 경우에는 Client Credentials Grant 같은 다른 흐름은 여전히 사용된다.

정리하자면, Authorization Code Grant 방식은 사용자의 비밀번호를 클라이언트가 직접 다루지 않으면서, 액세스 토큰 발급을 authorization response와 분리된 token point 교환 단계에서 처리할 수 있다는 점이 핵심이다.

여기에 PKCE를 결합하면 코드 탈취 및 주입 공격에 대한 방어가 강화되어, 현재의 기본 권장 흐름으로 자리 잡았다.

이러한 이유로 오늘날의 일반적인 로그인 및 제3자 위임 시나리오에서는 Authorization Code Grant 기반 구조가 사실상의 표준으로 자리잡고 있다.
특히 브라우저 기반 앱과 모바일 앱에서는 PKCE와 함께 사용하는것이 최신 권고와 부합한다.

마치며,

먼저, OAuth의 등장 배경과 가장 많이 사용되며 표준이 된 방식인 인가 코드 그랜트 방식까지 다루어 보았다. 다음으로는 이를 실제로 프로젝트에서 어떻게 구현을 했으며, 이어 OAuth 2.1에서는 어떤 변화가 있으며 이제 어떠한 방식으로 구현을 해야 하는지까지 정리해보고자 한다.

화이팅!

참고자료

profile
개발 참 즐겁습니다.

0개의 댓글