2025-09-22 00:59
-
OAuth는 비밀번호 없이 애플리케이션에 특정 자원에 대한 접근 권한을 안전하게 부여하는 위임(Delegation) 프로토콜이다.
-
리소스 소유자, 클라이언트, 권한 부여 서버, 리소스 서버의 네 가지 역할과 토큰(Token)을 기반으로 동작한다.
-
소셜 로그인부터 API 보안까지 현대 웹 생태계의 인증과 권한 부여의 핵심 표준으로, 다양한 방식(Grant Type)을 통해 유연성을 제공한다.
OAuth 2.0 완전 정복 A부터 Z까지 완벽 가이드
오늘날 우리는 수많은 웹사이트와 애플리케이션을 사용한다. 사진 편집 앱이 구글 포토에 있는 사진을 가져오고, 일정 관리 서비스가 회사 캘린더에 자동으로 회의를 등록하는 것은 이제 일상이 되었다. 이 모든 편리함의 이면에는 사용자의 비밀번호를 직접 공유하지 않고도 안전하게 데이터를 연결하는 강력한 기술이 숨어있다. 그 기술의 이름이 바로 OAuth이다.
“구글 계정으로 로그인하기”, “카카오로 계속하기” 버튼을 한 번이라도 눌러봤다면 당신은 이미 OAuth의 사용자다. 이 핸드북은 개발자뿐만 아니라 현대 디지털 서비스의 작동 원리를 이해하고 싶은 모든 이를 위해 OAuth가 무엇인지, 왜 만들어졌는지, 그리고 어떻게 우리의 디지털 생활을 안전하게 지켜주는지 A부터 Z까지 상세하게 안내한다.
1. OAuth의 탄생 배경 비밀번호 공유의 악몽
OAuth가 없던 시절을 상상해 보자. 만약 A라는 사진 인화 서비스가 당신의 구글 포토에 있는 사진을 인화해주고 싶다면, A 서비스는 당신에게 무엇을 요구했을까? 바로 구글 아이디와 비밀번호 그 자체였을 것이다.
이 방식은 몇 가지 치명적인 문제를 안고 있다.
-
과도한 권한 부여: A 서비스는 사진을 읽는 권한만 필요한데, 비밀번호를 넘겨주는 순간 당신의 이메일, 주소록, 클라우드 파일 등 모든 데이터에 접근할 권한을 갖게 된다. 이는 마치 집 현관문 열쇠만 주면 되는데, 집문서와 금고 비밀번호까지 모두 넘겨주는 것과 같다.
-
보안 취약점: 만약 A 서비스가 해킹당하면, 당신의 구글 계정 정보는 그대로 유출된다. 또한, A 서비스가 악의적인 의도를 가지고 당신의 계정으로 스팸 메일을 보내거나 데이터를 삭제할 수도 있다.
-
관리의 어려움: 당신이 비밀번호를 변경하면, 비밀번호를 공유했던 모든 서비스에 접속해 새로운 비밀번호를 다시 입력해야 한다. 어떤 서비스에 내 비밀번호를 공유했는지 기억하는 것조차 벅찬 일이다.
이러한 문제들을 ‘비밀번호 공유 안티패턴(Password Sharing Anti-Pattern)‘이라 부른다. OAuth는 바로 이 문제를 해결하기 위해 등장했다. 핵심 아이디어는 **‘위임(Delegation)‘**이다. 즉, 사용자가 자신의 자격증명(비밀번호)을 직접 주지 않고, 특정 서비스가 자신을 대신해 특정 자원에 접근할 수 있도록 제한된 권한을 가진 접근 허가증(토큰)을 발급해주는 표준적인 방법을 정의한 것이다.
2. OAuth 2.0의 핵심 구조 배우와 무대
OAuth의 동작 방식을 이해하기 위해선 먼저 무대 위에 등장하는 4명의 ‘배우’와 그들이 사용하는 핵심 ‘소품’을 알아야 한다.
핵심 역할(Roles)
| 역할 (Role) | 설명 | 비유 (호텔 발레파킹) |
|---|---|---|
| 리소스 소유자 (Resource Owner) | 데이터의 주인. 최종 사용자(End-user). | 자동차 주인 |
| 클라이언트 (Client) | 리소스 소유자를 대신해 특정 리소스에 접근하려는 애플리케이션. | 발레파킹 직원 |
| 권한 부여 서버 (Authorization Server) | 리소스 소유자를 인증하고, 클라이언트에게 접근 토큰을 발급하는 서버. | 호텔 프론트 데스크 직원 |
| 리소스 서버 (Resource Server) | 보호된 리소스(데이터)를 저장하고 있는 서버. API 서버. | 호텔 주차장 관리인 |
핵심 소품(Tokens)
OAuth의 흐름 속에서 권한을 증명하기 위해 다양한 종류의 ‘토큰’이라는 소품이 사용된다.
-
접근 토큰 (Access Token)
-
역할: 클라이언트가 리소스 서버에 접근할 때 사용하는 열쇠.
-
특징: 수명이 짧다(Short-lived). 보통 몇 분에서 몇 시간 정도의 유효기간을 가지며, 탈취되더라도 피해를 최소화할 수 있다. 내용 자체는 서버만 이해할 수 있는 임의의 문자열일 수도 있고, JWT처럼 자체적으로 정보를 담고 있을 수도 있다.
-
비유: 특정 시간 동안만 유효한 호텔 객실 키카드.
-
-
갱신 토큰 (Refresh Token)
-
역할: 접근 토큰이 만료되었을 때, 새로운 접근 토큰을 발급받기 위해 사용하는 장기 자격증명.
-
특징: 수명이 길다(Long-lived). 접근 토큰보다 훨씬 긴 유효기간을 가지며, 안전하게 보관되어야 한다. 사용자는 매번 로그인할 필요 없이, 클라이언트가 갱신 토큰을 이용해 조용히 새로운 접근 토큰을 받아와 서비스를 계속 이용할 수 있게 해준다.
-
비유: 호텔에 장기 투숙을 증명하는 투숙 확인증. 키카드가 만료되면 프론트 데스크에 투숙 확인증을 보여주고 새 키카드를 발급받을 수 있다.
-
-
ID 토큰 (ID Token)
-
역할: 사용자가 누구인지에 대한 인증(Authentication) 정보를 담고 있는 토큰.
-
특징: **OpenID Connect(OIDC)**라는 OAuth 2.0 위에 구축된 별도의 프로토콜에서 사용된다. JWT(JSON Web Token) 형식을 따르며, 사용자의 ID, 이메일, 이름 등의 정보를 포함한다. 클라이언트는 이 토큰을 통해 사용자가 누구인지 확인할 수 있다.
-
핵심: OAuth는 ‘권한 부여(Authorization)‘에, OIDC는 ‘인증(Authentication)‘에 초점을 맞춘다. “카카오로 로그인”은 인증(OIDC)과 권한 부여(OAuth)가 함께 일어나는 대표적인 예다.
-
3. OAuth 2.0 사용법 시나리오별 권한 부여 방식(Grant Types)
OAuth는 클라이언트의 종류와 사용 환경에 따라 다양한 권한 부여 시나리오를 제공한다. 이를 ‘Grant Type’이라고 부른다. 어떤 Grant Type을 사용하느냐에 따라 OAuth의 전체 흐름이 달라진다.
1) Authorization Code Grant (with PKCE) 가장 안전하고 표준적인 방법
서버를 가진 웹 애플리케이션이나 모바일/데스크톱 앱에서 가장 널리 사용되는 가장 안전한 방식이다. 특히 오늘날에는 PKCE(Proof Key for Code Exchange) 확장이 거의 필수로 사용된다.
흐름 요약: 클라이언트가 직접 접근 토큰을 받지 않고, 중간 다리 역할인 ‘권한 부여 코드(Authorization Code)‘를 먼저 받은 뒤, 이 코드를 서버 간의 안전한 통신을 통해 접근 토큰과 교환하는 방식이다.
단계별 흐름:
-
(클라이언트 → 리소스 소유자): 사용자가 “구글 계정으로 로그인” 버튼을 클릭한다.
-
(클라이언트 → 권한 부여 서버): 브라우저는 사용자를 구글의 권한 부여 서버로 리디렉션시킨다. 이때 클라이언트 ID, 리디렉션 URI, 요청 범위(scope), 그리고
code_challenge(PKCE용 암호화된 값) 등을 쿼리 파라미터로 함께 보낸다.- PKCE란? 중간에 권한 부여 코드가 탈취되더라도, 공격자가 원본 값(
code_verifier)을 모르기 때문에 토큰으로 교환할 수 없도록 만드는 보안 장치. 모바일 앱이나 SPA처럼 클라이언트 시크릿을 안전하게 저장하기 어려운 환경에서 필수적이다.
- PKCE란? 중간에 권한 부여 코드가 탈취되더라도, 공격자가 원본 값(
-
(리소스 소유자 ↔ 권한 부여 서버): 사용자는 구글 로그인 페이지에서 아이디/비밀번호를 입력하여 인증하고, “이 앱이 당신의 기본 프로필 정보에 접근하는 것을 허용하시겠습니까?”와 같은 동의 화면에서 ‘허용’을 클릭한다.
-
(권한 부여 서버 → 클라이언트): 권한 부여 서버는 사용자를 클라이언트가 미리 등록해 둔 ‘리디렉션 URI’로 다시 돌려보낸다. 이때 URL에 **‘권한 부여 코드(Authorization Code)‘**를 포함시킨다. 이 코드는 일회용이며 수명이 매우 짧다.
-
(클라이언트 서버 → 권한 부여 서버): 클라이언트의 백엔드 서버는 방금 받은 권한 부여 코드를 클라이언트 ID, 클라이언트 시크릿, 그리고 PKCE를 위한
code_verifier(원본 값)와 함께 권한 부여 서버로 보낸다. 이 통신은 브라우저를 거치지 않는 서버 간의 안전한 통신(Back-channel)이다. -
(권한 부여 서버 → 클라이언트 서버): 권한 부여 서버는 모든 정보가 유효한지(코드, 클라이언트 시크릿,
code_verifier등) 검증한 후, 마침내 **접근 토큰(Access Token)**과 **갱신 토큰(Refresh Token)**을 발급한다. -
(클라이언트 → 리소스 서버): 클라이언트는 이제 발급받은 접근 토큰을 HTTP 요청의
Authorization헤더에 담아 리소스 서버(예: 구글 프로필 API)에 보내 원하는 데이터를 요청한다. -
(리소스 서버 → 클라이언트): 리소스 서버는 접근 토큰이 유효한지 확인하고, 유효하다면 요청받은 데이터를 클라이언트에게 응답한다.
2) Client Credentials Grant 사용자가 없는 기계 간 통신
사용자의 개입 없이 애플리케이션(클라이언트) 자체가 소유한 리소스에 접근할 때 사용된다. 예를 들어, 주문 처리 서버가 결제 API 서버와 통신하거나, 데이터 분석 서비스가 다른 서비스의 통계 API를 호출하는 경우에 적합하다.
흐름 요약: 클라이언트가 자신의 ID와 시크릿으로 직접 권한 부여 서버에 인증하여 접근 토큰을 발급받는다. 리소스 소유자의 개입이 전혀 없다.
3) Legacy Grant Types (현재는 사용 비권장)
과거에는 다른 Grant Type들도 있었지만, 현재는 보안상의 이유로 대부분 사용되지 않거나 특정 상황에서만 제한적으로 사용된다.
-
Implicit Grant: 과거 SPA(Single Page Application)에서 사용되었으나, 접근 토큰이 URL을 통해 브라우저에 직접 노출되어 보안에 매우 취약하다. 현재는 Authorization Code Grant with PKCE 방식으로 완전히 대체되었다.
-
Resource Owner Password Credentials Grant: 사용자가 클라이언트에게 직접 아이디와 비밀번호를 제공하는 방식. OAuth의 근본 철학에 위배되며, 서비스 제공자가 직접 만든 앱처럼 클라이언트를 완전히 신뢰할 수 있는 극히 제한적인 경우에만 사용되어야 한다.
4. OAuth 심화 내용 더 깊은 이해를 위하여
범위(Scope)와 최소 권한의 원칙
OAuth 요청 시 클라이언트는 scope라는 파라미터를 통해 자신이 필요한 권한의 범위를 명시할 수 있다. 예를 들어, scope=profile_read calendar_write와 같이 요청하면, 사용자는 동의 화면에서 “이 앱이 프로필 읽기와 캘린더 쓰기 권한을 요청합니다”라는 명확한 내용을 확인할 수 있다.
이는 **‘최소 권한의 원칙(Principle of Least Privilege)‘**을 구현하는 핵심적인 방법이다. 클라이언트는 기능 수행에 필요한 최소한의 권한만 요청해야 하며, 사용자는 이를 보고 동의 여부를 결정할 수 있어 보안성이 크게 향상된다.
OAuth와 OpenID Connect (OIDC)의 관계
많은 사람들이 OAuth와 OIDC를 혼동하지만, 둘은 명확히 다른 목적을 가진다.
-
OAuth 2.0: **권한 부여(Authorization)**를 위한 프레임워크. “당신은 이 앱을 통해 내 구글 캘린더에 일정을 추가할 수 있습니다.”
-
OpenID Connect (OIDC): OAuth 2.0 위에 구축된 인증(Authentication) 계층. “당신은 홍길동이라는 구글 사용자임이 확인되었습니다.”
쉽게 말해, OIDC는 OAuth 2.0의 확장팩이다. OIDC는 scope=openid 요청을 통해 ID 토큰을 추가로 발급하며, 이 ID 토큰(JWT 형식) 안에는 사용자가 누구인지 증명하는 정보가 담겨 있다. 우리가 흔히 보는 ‘소셜 로그인’ 기능은 사실상 OIDC를 통해 구현되는 것이다.
보안 고려사항
OAuth는 강력하지만, 잘못 구현하면 여전히 보안 위협에 노출될 수 있다.
-
리디렉션 URI 검증: 권한 부여 서버는 반드시 사전에 등록된 리디렉션 URI로만 코드를 보내야 한다. 그렇지 않으면 공격자의 사이트로 코드가 탈취될 수 있다.
-
State 파라미터: 클라이언트는 권한 부여 요청 시 예측 불가능한
state값을 함께 보내고, 리디렉션 시 이 값이 그대로 돌아왔는지 확인해야 한다. 이는 CSRF(Cross-Site Request Forgery) 공격을 방지하는 데 도움을 준다. -
HTTPS 사용: OAuth의 모든 통신은 반드시 TLS(HTTPS)로 암호화되어야 한다. 토큰이나 코드가 중간에 탈취되는 것을 막기 위한 필수 조치다.
-
토큰 저장: 클라이언트는 획득한 토큰을 안전하게 저장해야 한다. 특히 브라우저 환경에서는
localStorage보다는HttpOnly쿠키나 메모리에 저장하는 것이 더 안전한 대안으로 권장된다.
결론 OAuth, 보이지 않는 디지털 세상의 문지기
OAuth 2.0은 단순히 ‘소셜 로그인’을 위한 기술이 아니다. 그것은 신뢰를 기반으로 서로 다른 서비스들이 안전하게 소통하고 데이터를 공유할 수 있게 만드는 현대 디지털 생태계의 핵심 인프라다. 사용자는 더 이상 자신의 가장 민감한 정보인 비밀번호를 아무 데나 넘겨주지 않아도 되고, 개발자는 안전하고 표준화된 방식으로 강력한 연동 기능을 구현할 수 있게 되었다.
이 핸드북을 통해 OAuth의 복잡해 보이는 흐름 뒤에 숨겨진 명확한 역할과 규칙, 그리고 그것이 우리의 온라인 생활을 어떻게 더 안전하고 편리하게 만드는지 이해했기를 바란다. 다음에 “구글 계정으로 로그인” 버튼을 누를 때, 당신은 화면 뒤에서 벌어지는 이 정교하고 우아한 ‘권한 위임’의 과정을 떠올릴 수 있을 것이다.