OAuth 2.0: 정의 및 인가 프로토콜 작동 방식

저자: IT Sectr 게시일: 2026-04-05 읽는 시간: 10 분

OAuth 2.0은 타사 애플리케이션에 사용자의 자격 증명을 공유하지 않고 해당 리소스에 대한 제한된 액세스를 제공하는 업계 표준 인가 프로토콜입니다. 이 프로토콜은 웹 및 모바일 애플리케이션에서 위임된 인가의 사실상 표준이 되었으며, Google, Facebook, Apple, GitHub와 같은 플랫폼에서 사용됩니다. IETF RFC 6749(2025)에 따르면, OAuth 2.0은 위임된 데이터 액세스가 필요한 모든 API 통합의 85% 이상에서 사용됩니다.

주요 내용

  • OAuth 2.0은 비밀번호를 전송하지 않고 애플리케이션이 사용자 리소스에 액세스할 수 있도록 하는 위임된 인가 프로토콜입니다(IETF RFC 6749)
  • Access Token은 사용자 인증 성공 후 인가 서버가 애플리케이션에 발급하는 임시 액세스 토큰입니다
  • Authorization Code Flow는 모바일 애플리케이션에 가장 안전한 Grant Type으로, 코드 챌린지(PKCE)를 사용하여 가로채기로부터 보호합니다
  • Refresh Token은 사용자가 다시 로그인할 필요 없이 새 Access Token을 얻기 위한 장기 수명 토큰입니다
  • AppAuth는 Android 및 iOS의 네이티브 모바일 애플리케이션에서 OAuth 2.0을 구현하기 위한 IETF 권장 라이브러리입니다

OAuth 2.0이란?

OAuth 2.0은 IETF RFC 6749에 정의된 인가 프로토콜로, 타사 애플리케이션이 사용자의 사용자 이름과 비밀번호를 노출하지 않고 해당 리소스에 대한 제한된 액세스를 얻을 수 있도록 합니다. 이 프로토콜은 비밀번호 모델의 근본적인 문제를 해결합니다: 비밀번호를 신뢰하는 애플리케이션은 모든 계정 데이터에 대한 무제한 액세스를 얻습니다. OAuth 2.0은 명시적으로 제한된 액세스 범위를 가진 임시 토큰을 발급하여 이 접근 방식을 대체합니다.

OAuth 2.0의 아키텍처는 위임된 인가입니다. 사용자(Resource Owner)는 중개자: 인가 서버(Authorization Server)를 통해 리소스 서버(Resource Server)에 저장된 자신의 데이터에 액세스할 수 있도록 애플리케이션(Client)을 인가합니다. 인가 서버는 Access Token을 발급합니다: 애플리케이션이 데이터에 액세스하기 위해 리소스 서버에 제시하는 암호화 문자열입니다. OAuth 2.0과 SAML 또는 OpenID Connect의 중요한 차이점: OAuth 2.0은 인가 작업(무엇이 허용되는지)을 해결하고, 인증(사용자가 누구인지)은 해결하지 않습니다. 인증을 위해 OAuth 2.0 위에 OpenID Connect(OIDC) 프로토콜이 구축됩니다.

이 프로토콜은 모든 주요 플랫폼에서 지원됩니다. Google은 Google APIs(Gmail, Drive, Calendar) 액세스에 OAuth 2.0을 사용하고, Facebook은 Graph API에, Apple은 Sign in with Apple(ASAuthorizationAppleIDProvider)에, GitHub는 리포지토리 액세스에 사용합니다. 모바일 개발의 맥락에서 OAuth 2.0은 타사 서비스를 통합하는 표준 메커니즘입니다: 소셜 네트워크를 통한 로그인, 클라우드 스토리지 액세스, 사용자를 대신한 콘텐츠 게시 등이 있습니다.

OAuth 2.0의 역할 및 구성 요소

OAuth 2.0 프로토콜은 상호 작용이 완전한 인가 주기를 형성하는 네 가지 역할을 정의합니다. 모바일 애플리케이션에서 프로토콜을 올바르게 구현하려면 각 역할을 이해하는 것이 필수적입니다.

프로토콜의 네 가지 역할

역할설명예시
Resource Owner데이터 소유자: 자신의 리소스에 대한 액세스를 허용하는 사용자“Google로 로그인”을 클릭하는 애플리케이션 사용자
Client소유자를 대신하여 리소스에 대한 액세스를 요청하는 애플리케이션Google Drive 액세스가 필요한 모바일 앱
Authorization Server인증 및 인가 후 토큰을 발급하는 서버accounts.google.com: Google의 인가 서버
Resource Server토큰을 통해 보호된 리소스에 대한 액세스를 제공하는 APIwww.googleapis.com: Google Drive API의 리소스 서버

프로토콜의 주요 엔터티는 Access Token, Refresh TokenAuthorization Code입니다. Access Token은 수명이 짧은 토큰(보통 15–60분)으로, 각 데이터 요청과 함께 리소스 서버에 제시됩니다. Refresh Token은 수명이 긴 토큰(일 또는 주)으로, 사용자가 다시 로그인할 필요 없이 새 Access Token을 얻는 데 사용됩니다. Authorization Code는 사용자 인가 후 발급되는 임시 코드로, Access Token 및 Refresh Token과 교환됩니다.

Grant Types: 인가 시나리오

OAuth 2.0은 여러 Grant Types(토큰 획득 시나리오)를 정의하며, 각각은 특정 클라이언트 유형 및 보안 컨텍스트에 맞게 설계되었습니다. 모바일 애플리케이션에서 인가를 설계할 때 올바른 Grant Type을 선택하는 것은 중요한 아키텍처 결정입니다.

주요 Grant Types는 다음과 같습니다: Authorization Code(서버 구성 요소가 있는 모바일 및 웹 애플리케이션에 가장 안전), PKCE가 적용된 Authorization Code(Proof Key for Code Exchange: 서버 백엔드가 없는 모바일 및 SPA 애플리케이션용), Client Credentials(사용자 참여 없는 서버 간 인증용), Resource Owner Password Credentials(비권장: 비밀번호를 직접 전송). OAuth Security BCP(RFC 9700) 권장 사항에 따라 PKCE는 공개 클라이언트(모바일 애플리케이션, SPA)에 필수 확장입니다.

주요 Grant Types

  • Authorization Code + PKCE: 네이티브 모바일 애플리케이션에 권장되는 Grant Type입니다. 클라이언트는 암호화된 code_verifier를 생성하고, code_challenge(SHA-256 해시)를 계산하며, 서버는 코드를 토큰과 교환할 때 일치 여부를 확인합니다. 이는 애플리케이션과 서버 간의 authorization code 가로채기를 방지합니다
  • Client Credentials: 클라이언트가 알려져 있고 인증된 기계 간 인가에 사용됩니다. 애플리케이션은 client_id 및 client_secret을 사용하여 토큰을 얻습니다. 사용자 참여가 필요하지 않습니다. 일반적인 시나리오: 서버 애플리케이션이 배치 데이터 처리를 위해 API를 호출합니다
  • Device Authorization Grant: 브라우저가 없는 장치(Smart TV, IoT)용입니다. 사용자는 다른 장치에서 링크를 따라가서 코드를 입력합니다. 예를 들어, 스마트폰을 통해 TV에서 Netflix를 인가할 때 사용됩니다
  • Resource Owner Password Credentials: OAuth Security BCP에서 금지된 비권장 Grant Type입니다. 비밀번호가 클라이언트에 직접 전송되어 제로 지식 인증 원칙을 위반합니다. 레거시 시스템에서 마이그레이션하는 경우에만 사용됩니다

모바일 애플리케이션을 위한 PKCE가 적용된 Authorization Code Flow

PKCE가 적용된 Authorization Code Flow는 네이티브 모바일 애플리케이션에 권장되는 OAuth 2.0 구성입니다. PKCE(Proof Key for Code Exchange)는 authorization code 가로채기 공격을 방지하는 추가 보호 계층을 추가합니다. 이 프로토콜은 IETF RFC 7636에 설명되어 있습니다.

PKCE 단계별 절차

단계 순서: (1) 클라이언트가 임의의 code_verifier를 생성합니다(예약되지 않은 문자만 사용하는 43–128자 문자열), (2) 클라이언트가 code_challenge = SHA-256(code_verifier)를 계산합니다, (3) 클라이언트가 code_challenge를 전달하여 Authorization Server에서 사용자 인가를 위해 브라우저를 엽니다, (4) 인가 성공 후 서버가 사용자 정의 URI 체계(앱 딥 링크)를 통해 애플리케이션에 authorization code를 반환합니다, (5) 클라이언트가 authorization code + code_verifier를 서버에 전송합니다, (6) 서버가 SHA-256(code_verifier) === code_challenge를 확인하고 Access Token + Refresh Token을 발급합니다.

PKCE의 장점: 공격자가 URI 체계에서 authorization code를 가로채더라도, 합법적인 클라이언트만 아는 code_verifier 없이는 토큰과 교환할 수 없습니다. 모바일 애플리케이션에서 브라우저를 열려면 Chrome Custom Tabs(Android) 또는 ASWebAuthenticationSession(iOS)을 사용해야 합니다. 이렇게 하면 시스템 브라우저가 애플리케이션의 메모리에서 code_verifier에 액세스할 수 없습니다.

AppAuth를 통한 Android에서의 OAuth 2.0 구현

AppAuth는 IETF에서 권장하는 네이티브 애플리케이션을 위한 OAuth 2.0 및 OpenID Connect의 참조 구현입니다. 이 라이브러리는 PKCE, Chrome Custom Tabs, authorization code 반환을 위한 사용자 정의 URI 체계 및 자동 토큰 갱신을 지원합니다. Android용 AppAuth는 `net.openid:appauth:0.11.1` 종속성을 통해 사용할 수 있습니다.

kotlin
val serviceConfig = AuthorizationServiceConfiguration.fromUrl(
    Uri.parse("https://accounts.google.com/.well-known/openid-configuration")
)

val request = AuthorizationRequest.Builder(
    serviceConfig,
    "CLIENT_ID.apps.googleusercontent.com",
    ResponseTypeValues.CODE,
    Uri.parse("com.example.app:/oauth2callback")
)
.setScope("openid profile email")
.setCodeVerifier(
    CodeVerifierUtil.generateRandomCodeVerifier()
)
.build()

val authService = AuthorizationService(context)
val intent = authService.getAuthorizationRequestIntent(request)

// 인증을 위해 Chrome Custom Tab 실행
startActivityForResult(intent, REQUEST_CODE_AUTH)

authorization code(onActivityResult)를 수신한 후, 애플리케이션은 TokenRequest를 통해 이를 Access Token 및 Refresh Token과 교환합니다. 토큰은 EncryptedSharedPreferences(Android Security Crypto)를 통한 암호화와 함께 SharedPreferences에 저장됩니다. Refresh Token은 KeyStore(하드웨어 기반 키 저장소로 다른 애플리케이션이 액세스할 수 없음)에 저장해야 합니다. Access Token이 만료될 때마다 애플리케이션은 Refresh Token을 사용하여 새 토큰을 얻습니다: 사용자는 다시 인증할 필요가 없습니다.

kotlin
// authorization code를 토큰으로 교환
val data = intent?.data ?: return
val resp = AuthorizationResponse.fromIntent(data)
val exchangeReq = resp?.createTokenExchangeRequest()
    ?: return

authService.performTokenRequest(
    exchangeReq,
    ClientAuthentication.none()
) { tokenResp, ex ->
    if (tokenResp != null) {
        // Access Token 및 Refresh Token 수신됨
        val accessToken = tokenResp.accessToken
        val refreshToken = tokenResp.refreshToken
        // EncryptedSharedPreferences에 저장
        saveTokens(accessToken, refreshToken)
    }
}

위 코드는 PKCE가 적용된 완전한 OAuth 2.0 흐름을 보여줍니다: OpenID Connect Discovery를 통한 서버 구성 생성, code_verifier가 포함된 인가 요청 생성, Chrome Custom Tab 시작, 사용자 정의 URI 체계를 통한 authorization code 수신, Token Request를 통한 코드-토큰 교환. Access Token 만료 처리는 중요합니다: Resource Server에서 HTTP 401 응답을 받으면, 애플리케이션은 Refresh Token을 사용하여 새 Access Token을 얻고 요청을 다시 실행해야 합니다.

OAuth 2.0 보안: 일반적인 공격 및 보호

OAuth 2.0은 많은 공격 벡터를 가진 복잡한 프로토콜입니다. IETF Security BCP(RFC 9700)는 OAuth 2.0 취약점의 20개 이상의 클래스를 설명합니다. 모바일 애플리케이션의 경우 가장 중요한 것은: 사용자 정의 URI 체계를 통한 authorization code 가로채기, 콜백 엔드포인트에 대한 CSRF 공격, 안전하지 않은 저장소에서 Refresh Token 도난, 인텐트 가로채기를 통한 클라이언트 가장입니다.

이러한 공격에 대한 보호에는 필수 조치가 포함됩니다: (1) S256 code_challenge가 있는 PKCE: URI 체계가 가로채져도 authorization code 가로채기를 방지합니다. (2) CSRF 방지를 위한 nonce 또는 state 매개변수 사용: 서버는 authorization code가 원래 요청과 일치하는지 확인합니다. (3) KeyStore(Android) 또는 Keychain(iOS)에만 Refresh Token 저장: SharedPreferences나 UserDefaults에는 저장하지 않습니다. (4) 전송 계층에서 MITM 보호를 위한 Certificate Pinning이 있는 TLS 사용. (5) redirect_uri 검증: 인가 서버는 등록된 URI와의 일치를 엄격히 검증해야 합니다.

IETF의 추가 권장 사항: 모바일 애플리케이션은 보안 감사를 통과한 AppAuth 또는 유사한 라이브러리를 사용해야 합니다. OAuth에 WebView를 사용하지 마십시오(WebView는 기본 애플리케이션에서 데이터를 격리하지 않습니다). 자동 Refresh Token 순환을 구현하십시오(각 Refresh Token은 한 번만 사용할 수 있음). Android의 경우 TrustManager, iOS의 경우 URLSession을 통해 Certificate Pinning을 추가하십시오. OpenID Connect Discovery(well-known 엔드포인트)는 인가 서버의 올바른 엔드포인트를 자동으로 결정하고 피싱 페이지로의 리디렉션을 방지하는 데 도움이 됩니다.

자주 묻는 질문

OAuth 2.0과 OpenID Connect의 차이점은 무엇인가요?

OAuth 2.0은 인가 프로토콜(무엇을 할 수 있는가?)이고, OpenID Connect(OIDC)는 인증 프로토콜(사용자가 누구인가?)입니다. OIDC는 OAuth 2.0 위에 구축되며 ID Token(사용자 ID 정보가 포함된 JWT 토큰)을 추가합니다. OAuth 2.0은 Access Token을 제공하고, OIDC는 ID Token과 사용자 프로필을 얻기 위한 UserInfo 엔드포인트로 이를 보완합니다.

Bearer Token이란 무엇이며 왜 위험한가요?

Bearer Token은 HTTP 헤더 Authorization: Bearer에 제시되는 Access Token입니다. 위험성은 토큰을 가진 사람이라면 누구나 리소스에 액세스할 수 있다는 데 있습니다: 토큰이 클라이언트에 바인딩되지 않습니다. 따라서 Bearer Token은 TLS(HTTPS)를 통해서만 전송되어야 하며, 수명이 짧고(15–60분), 로그나 URL 매개변수에 절대 저장되어서는 안 됩니다.

모바일 애플리케이션에 PKCE가 필수인 이유는 무엇인가요?

모바일 애플리케이션은 client_secret이 없는 공개 클라이언트입니다(APK/IPA에서 비밀을 보호할 수 없음). PKCE가 없으면 공격자가 사용자 정의 URI 체계(예: malformed://callback?code=ABC)를 통해 authorization code를 가로채서 토큰과 교환할 수 있습니다. PKCE는 애플리케이션만 아는 code_verifier를 추가하여 가로챈 코드를 무용지물로 만듭니다.

Access Token은 얼마나 자주 갱신해야 하나요?

일반적인 Access Token의 수명은 15–60분입니다(인가 서버에서 구성 가능). Resource Server에 대한 각 HTTP 요청과 함께 응답이 확인됩니다: 코드가 401이면, 애플리케이션이 Refresh Token Flow를 트리거하여 새 Access Token을 얻습니다. Refresh Token의 수명은 제공자의 보안 정책에 따라 24시간에서 몇 개월까지입니다. Refresh Token이 변경되면 이전 것은 무효화됩니다.

OAuth 2.0에 WebView를 사용할 수 있나요?

아니요: IETF Security BCP(RFC 9700)는 모바일 애플리케이션에서 OAuth 2.0에 WebView 사용을 금지합니다. WebView는 기본 애플리케이션에서 쿠키와 데이터를 격리하지 않아, 애플리케이션이 사용자의 자격 증명을 가로챌 수 있습니다. WebView 대신 Chrome Custom Tabs(Android) 또는 ASWebAuthenticationSession(iOS)을 사용하세요: 애플리케이션에서 격리된 시스템 브라우저 구성 요소입니다.

요약

  • OAuth 2.0은 제한된 액세스 범위를 가진 임시 토큰으로 비밀번호 전송을 대체하는 위임된 인가 프로토콜입니다(IETF RFC 6749)
  • Authorization Code + PKCE는 URI 체계를 통한 authorization code 가로채기로부터 보호하는 모바일 애플리케이션 필수 Grant Type입니다
  • Access Token은 각 데이터 요청과 함께 Resource Server에 제시되는 수명이 짧은 토큰(15–60분)입니다
  • Refresh Token은 사용자 재로그인 없이 Access Token을 원활하게 갱신하기 위한 장기 수명 토큰입니다
  • AppAuth는 PKCE, Custom Tabs 및 KeyStore를 지원하는 Android 및 iOS용 참조 OAuth 2.0 라이브러리입니다
  • WebView는 금지됨: IETF RFC 9700에 따라 OAuth 2.0은 시스템 브라우저(Custom Tabs / ASWebAuthenticationSession)를 통해 수행해야 합니다
  • OpenID Connect는 OAuth 2.0 위에 구축된 인증 프로토콜로, 사용자 식별을 위한 ID Token(JWT)을 추가합니다

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기