학습 목적
당연하게 사용만 해왔던 OAuth의 발전과정을 보고 OAuth의 다양한 인증방식의 차이를 알아보자. 이를 통해 상황에 맞는 인증방식을 선택할 수 있도록 하자
OAuth란?
OAuth는 Open Authorization의 약자로 웹 및 애플리케이션 인증 및 권한 부여를 위한 개방형 표준입니다. 애플리케이션이 특정 시스템의 보호된 리소스에 접근하기 위해서, 사용자 인증을 통해 사용자의 리소스 접근 권한을 위임받을 수 있게 합니다.
OAuth 1.0
주요 요소
- User: 자신의 자원을 제3의 애플리케이션에게 접근을 허용하는 사용자
- Consumer: 자원 소유자의 데이터를 접근하려고 하는 애플리케이션
- Service Provider: 자원 소유자의 데이터를 호스팅하는 서버로 요청 토큰과 접근 토큰을 관리
- Request Token: Consumer가 자원 소유자의 인가를 얻기 위해 먼저 받아야 하는 토큰
- Access Token: 자원 소유자가 인가한 후, Consumer가 보호된 자원에 접근하기 위해 사용하는 토큰
진행 흐름
- Consumer 등록: Consumer가 Consuer Key와 Consumer Secret 수령
- Request Token 요청: Consumer가 Consumer Key와 Secret으로 Service Provider에 요청 토큰을 요청
- Request Token 및 인증/인가를 진행할 URL 반환: Provider가 Client에게 요청 토큰을 발급하고 사용자가 인증/인가할 URL을 반환
- 사용자 인증/인가: Consumer가 사용자를 리다이렉트 시켜서 인증/인가 진행
- 검증 코드 수령: 인증/인가가 끝나면 Service Provider는 사용자를 Consumer의 콜백 URL로 리다이렉트 (요청 토큰과 검증 코드가 함께 전달)
- 액세스 토큰 수령: Consumer가 Provider에게 request token, consumer key, 서명 등을 포함하여 액세스 토큰 요청
- Consumer가 발급된 액세스 토큰으로 보호된 리소스에 접근
서명 생성 단계
1. 서명 base 문자열 생성 (HTTP 메서드, 요청 URL, 정렬된 요청 매개변수)
2. 서명 키 생성 (Consumer Secret과 Token Secret을 결합하여 서명 키를 생성
3. 서명 생성 (서명 base 문자열과 서명 키를 사용하여 HMAC-SHA1 등의 알고리즘으로 서명)
4. 매개변수에 포함하여 요청
OAuth 2.0 (vs 1.0)
변화한 점
- 구현 간소화: 복잡한 서명 과정 대신 HTTPS를 통한 보안 보장, JWT, PKCE와 같은 추가적인 보안 메커니즘을 통해 기능 확장 가능
- Scope 기능 추가: 해당 토큰이 어떤 접근 범위를 가지고 있는지 나타나게 됨
- Refresh Token 추가: Access Token의 만료 기간을 짧게 설정할 수 있게 되어 보안적으로 우수해짐
- 다양한 인증방식: 주로 서버 사이드 웹 애플리케이션을 대상으로 설계에서 모바일 및 다양한 클라이언트에서 사용할 수 있게 다양한 인증방식을 제공
인증 방식 목록
1. Authorization Code
2. Implicit
3. Resource Owner Password Credentials
4. Client Credentials
Authorization Code
- Access Token을 바로 클라이언트에게 전달하지 않아서 잠재적 유출을 방지
- state 파라미터를 통해서 csrf 공격으로부터의 보안을 강화
- PKCE (Proof Key for Code Exchange)를 통해서 중간자 공격을 방지
- Code의 유효기간을 짧게 하고 1회성으로 함으로써 보안 향상
Implcit
- 애플리케이션이 액세스 토큰을 즉시 받을 수 있는 방식
- 인가서버가 URI의 fragment를 통해서 클라이언트에 반환, 이를 통해 새로고침 없이 브라우저가 URL을 변경할 수 있었지만 HTML5의 History API를 통해 새로고침 없이 업데이트할 수 있게 되어 더 이상 장점이 아니게 됨
- 액세스 토큰이 URL로 노출되게 되어 브라우저 히스토리, 로그, 레퍼러 헤더 등에 노출될 가능성이 있으며 중간자 공격에 취약
Resource Owner Password Credentials
- 클라이언트 어플리케이션이 사용자(자원 소유자)의 ID/Password를 직접 사용하여 액세스 토큰을 얻는 방식
- 클라이언트를 신뢰할 수 있는 환경에서의 사용이 권장
- 클라이언트 애플리케이션이 자신의 ID와 Secret을 사용하여 액세스 토큰을 얻는 방식
- 서버 간 통신을 수행할 때 사용 (데이터베이스, 내부 API 접근 등)
OAuth 2.1 (vs 2.0)

출처: oauth.net/2.1/
- 인증 코드 흐름을 사용하는 모든 OAuth 클라이언트에는 PKCE가 필요
- 리다이렉션 URI는 정확하게 문자열이 일치해야 함
- Implicit Grant 제거
- Resource Owner Password Credentials Grant 제거
- Bearer 토큰 사용 시, URL의 쿼리 문자열에 포함하는 방법 제거
- 공개 클라이언트를 위한 리프레시 토큰은 발신자 제약이 있거나 일회성으로 사용되어야 함
- 공개 클라이언트와 비공개 클라이언트의 정의는 클라이언트가 자격 증명을 가지고 있는지 여부를 참조하도록 단순화
전체적으로 보안 문제를 해결하고 2.0에서의 best practice를 반영하였다고 볼 수 있다.
여기서 PKCE에 대해서 더 자세하게 알아보자
PKCE (Proof Key for Code Exchange)란?

출처: What's New With OAuth and OIDC? - OktaDev
(www.youtube.com/watch?v=g_aVPdwBTfw&t=500s)
SPA의 경우 애플리케이션의 소스 코드가 브라우저 내에서 사용되고, Native Application은 디컴파일할 수 있기 때문에 클라이언트 자격증명을 안전하게 저장할 수 없다. 따라서 퍼블릭 클라이언트로 볼 수 있으며 이를 위해 Authorization Code Grant에서 PKCE를 사용해야 한다.
PKCE에서 사용되는 요소
- code_verifier: 인증 코드를 가로채도 사용하지 못하도록 하는 임의의 Random key
- code_challenge: code_verifier 값을 code_challenge_method로 hashing한 값
- code_challenge_method: code_challenge를 어떤 방식으로 변환할 것인지를 지정
PKCE 과정
- 클라이언트가 PKCE 수행 전, code_verifier와 code_challenge 값을 생성
- Authorization Server 측으로 code 인증 방식 요청과 code_challenge, code_challenge_method를 전송
- 인증이 완료된 후 redirect_uri에 code값을 포함되어 클라이언트에게 전달
- 전달받은 code값과 code_verifier를 통해 token 교환 요청
- Authorization 서버가 code_verifier를 code_challenge_method로 검증하고 일치하면 Access Token 발급
이를 통해 중간 공격자가 인증 코드를 가로채고, code_challenge를 가로채더라도 Access Token 을 획득할 수 없게 만들 수 있다.
이미지 출처
- oauth.net/2.1/
- What's New With OAuth and OIDC? - OktaDev
(www.youtube.com/watch?v=g_aVPdwBTfw&t=500s)