OAuth 2.0 권한 위임 흐름과 보안 설계

OAuth 2.0의 역할 분리, 권한 부여 방식, 토큰 관리와 리다이렉트 URI 검증 등 구현 시 보안 고려사항을 정리한다.

2026-08-14 · 최초 발행 2025-06-15

비밀번호를 전달하지 않는 권한 위임

OAuth 2.0은 인터넷 서비스 사이에서 제한된 접근 권한을 위임하기 위한 개방형 표준 프로토콜이다. 웹과 모바일 애플리케이션은 이 구조를 통해 사용자의 비밀번호를 직접 받지 않은 채 제3자 애플리케이션에 필요한 자원 접근을 허용할 수 있다.

이 흐름은 인증과 권한 부여를 담당하는 주체를 분리한다. 보호된 자원에 대한 결정 권한은 사용자에게 남기고, 클라이언트는 발급받은 토큰으로 필요한 범위에서만 자원을 요청한다.

권한을 나누는 주체들

OAuth 2.0 프레임워크에는 네 가지 역할이 있다.

  • Resource Owner(자원 소유자): 보호된 자원의 접근 권한을 승인할 수 있는 개체이며, 일반적으로 최종 사용자다.
  • Client(클라이언트): 자원 소유자를 대신해 보호된 자원에 접근하려는 애플리케이션이다.
  • Authorization Server(권한 부여 서버): 자원 소유자의 인증과 권한 승인을 확인한 뒤 클라이언트에 접근 토큰을 발급한다.
  • Resource Server(자원 서버): 보호된 자원을 제공하며, 접근 토큰을 검증한 뒤 요청을 처리한다.

클라이언트가 자원을 요청하면 사용자는 권한 부여 서버에서 인증과 동의를 수행한다. 이후 클라이언트는 권한 부여 코드 또는 토큰을 받아 자원 서버에 접근한다.

Resource ServerAuthorization ServerClientResource OwnerResource ServerAuthorization ServerClientResource Owner권한 요청인증 및 권한 부여권한 부여 코드 전달권한 부여 코드로 액세스 토큰 요청액세스 토큰 발급액세스 토큰으로 자원 요청보호된 자원 제공

사용자 동의가 포함되는 권한 부여 방식

Authorization Code Grant

Authorization Code Grant는 제3자 서비스인 클라이언트가 권한을 요청할 때 쓰는 일반적이고 안전한 방식이다. 클라이언트는 먼저 권한 부여 코드를 받고, 클라이언트 인증을 거쳐 토큰으로 교환한다.

리소스 서버인증 서버클라이언트사용자리소스 서버인증 서버클라이언트사용자서비스 이용 요청권한 부여 요청로그인 및 권한 동의 요청로그인 및 권한 동의권한 부여 코드 전달코드 + 클라이언트 인증으로 토큰 요청액세스 토큰 + 리프레시 토큰 발급액세스 토큰으로 API 호출자원 응답

클라이언트 인증이 필요하고 리프레시 토큰을 지원한다. 웹 서버 애플리케이션이나 백엔드 서버가 있는 애플리케이션에 적합하며, Google, Facebook, GitHub 등의 소셜 로그인에서 사용된다.

Implicit Grant

Implicit Grant는 Authorization Code Grant에서 중간 코드 교환을 생략한 흐름이다. 권한 요청의 인증 절차를 간소화하려는 경우 사용한다.

리소스 서버인증 서버클라이언트(SPA)사용자리소스 서버인증 서버클라이언트(SPA)사용자서비스 이용 요청권한 부여 요청로그인 및 권한 동의 요청로그인 및 권한 동의URL 프래그먼트로 액세스 토큰 직접 전달액세스 토큰으로 API 호출자원 응답

토큰이 URL 프래그먼트로 직접 전달되므로 보안 위험이 있고, 리프레시 토큰도 지원하지 않는다. SPA(Single Page Application)나 모바일 앱에서 사용되었으며, 현재는 보안 문제로 사용을 권장하지 않는다. 레거시 자바스크립트 애플리케이션과 일부 모바일 앱이 사례다.

서비스 자체의 권한으로 토큰을 얻는 방식

Client Credentials Grant

Client Credentials Grant는 자원 소유자가 없거나 클라이언트가 자원 소유자인 상황에 사용한다. 사용자 개입 없이 클라이언트가 자신의 자격증명으로 토큰을 요청한다.

리소스 서버인증 서버클라이언트리소스 서버인증 서버클라이언트클라이언트 ID와 비밀키로 토큰 요청액세스 토큰 발급액세스 토큰으로 API 호출자원 응답

서버 간 통신에 적합하며, 마이크로서비스 아키텍처의 서비스 간 인증에도 활용된다. 백엔드 서비스 간 API 통신, 배치 작업, 시스템 관리 도구가 대표적인 사례다.

Resource Owner Password Credentials Grant

Resource Owner Password Credentials Grant는 사용자의 사용자명과 비밀번호를 클라이언트를 통해 직접 권한 부여 서버에 제공하는 방식이다.

리소스 서버인증 서버클라이언트사용자리소스 서버인증 서버클라이언트사용자사용자명과 비밀번호 제공사용자 자격증명 + 클라이언트 인증으로 토큰 요청액세스 토큰 + 리프레시 토큰 발급액세스 토큰으로 API 호출자원 응답

클라이언트가 사용자 자격증명에 직접 접근하므로 높은 신뢰관계가 필요한 경우에만 사용한다. 자사 개발 애플리케이션이나 레거시 시스템 마이그레이션에서 임시 솔루션으로 활용할 수 있지만, 보안 위험 때문에 가능하면 사용을 자제하는 편이 낫다.

토큰 발급 흐름에서 지킬 보안 조건

모든 OAuth 통신은 TLS/SSL을 사용해 암호화해야 한다. 권한 부여 요청에는 state 파라미터를 사용해 CSRF 공격을 방지하고, 등록된 리다이렉트 URI만 허용해 피싱 공격 가능성을 줄인다.

접근 토큰은 유효 기간을 제한하고 안전하게 저장해야 한다. 클라이언트 ID와 비밀키 역시 안전하게 관리해야 하며, 인증 실패나 토큰 만료 같은 상황에 대한 처리 방안도 준비할 필요가 있다.

OAuth 2.0 위에 더해지는 기능

OAuth 2.0은 여러 확장을 통해 범위를 넓힌다.

  • OpenID Connect: OAuth 2.0 위에 구축되는 ID 계층으로 인증 기능을 추가한다.
  • JWT(JSON Web Token): 자주 사용되는 토큰 형식이며 자체 검증 가능한 토큰을 제공한다.
  • PKCE(Proof Key for Code Exchange): 모바일 앱과 SPA를 위한 보안 확장이다.
  • OAuth 2.1: OAuth 2.0의 보안을 강화하는 버전으로 개발 중이다.

소셜 로그인에 연결하는 예시

소셜 로그인은 사용자가 Google, Facebook, GitHub 등의 계정으로 서비스에 로그인하도록 구성하는 OAuth 2.0 활용 사례다.

// 예: Node.js에서 Google OAuth 구현
const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth20").Strategy;

passport.use(
  new GoogleStrategy(
    {
      clientID: GOOGLE_CLIENT_ID,
      clientSecret: GOOGLE_CLIENT_SECRET,
      callbackURL: "http://www.example.com/auth/google/callback",
    },
    function (accessToken, refreshToken, profile, cb) {
      User.findOrCreate({ googleId: profile.id }, function (err, user) {
        return cb(err, user);
      });
    },
  ),
);

서비스 간 API 호출에 적용하는 예시

마이크로서비스 아키텍처에서는 Client Credentials Grant를 이용해 서비스 간 API 통신을 보호할 수 있다.

# 예: Python에서 서비스 간 인증
import requests

def get_service_token():
    token_url = "https://auth.example.com/oauth/token"
    client_id = "service_client_id"
    client_secret = "service_client_secret"

    payload = {
        "grant_type": "client_credentials",
        "client_id": client_id,
        "client_secret": client_secret
    }

    response = requests.post(token_url, data=payload)
    return response.json()["access_token"]

def call_protected_api():
    token = get_service_token()
    headers = {"Authorization": f"Bearer {token}"}
    api_response = requests.get("https://api.example.com/protected-resource", headers=headers)
    return api_response.json()

권한 부여 방식을 고를 때는 애플리케이션 유형과 보안 요구사항을 함께 봐야 한다. 토큰 저장 위치, 리프레시 메커니즘, 만료 처리 전략을 정하고, 권한 동의 화면의 명확성과 로그인 흐름의 단순성도 고려한다. GDPR, CCPA 등 데이터 보호 규정을 준수하는 방안 역시 설계에 포함해야 한다.

OAuth 2.0권한 위임접근 토큰인증 서버API 보안