OAuth2 Reference
OAuth2 플로우별 구현 가이드
Authorization Code Flow
서버 사이드 애플리케이션에서 가장 많이 사용되는 플로우. 클라이언트 시크릿을 안전하게 보관할 수 있는 환경에서 사용합니다.
사용 사례
웹 서버 애플리케이션, 백엔드 API
단계
- 1. 사용자를 인증 서버의 /authorize 엔드포인트로 리다이렉트
- 2. 사용자가 로그인 후 권한 승인
- 3. 인증 서버가 authorization code와 함께 redirect_uri로 리다이렉트
- 4. 서버에서 code를 /token 엔드포인트로 교환하여 access_token 획득
- 5. access_token으로 API 호출
흐름도
User -> App -> Auth Server (/authorize)
Auth Server -> User (로그인 화면)
User -> Auth Server (인증)
Auth Server -> App (code)
App -> Auth Server (/token + code + client_secret)
Auth Server -> App (access_token)코드 예시
// 1. 인증 URL 생성
const authUrl = new URL('https://auth.example.com/authorize');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', CLIENT_ID);
authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
authUrl.searchParams.set('scope', 'openid profile email');
authUrl.searchParams.set('state', generateRandomState());
// 2. 콜백에서 code를 token으로 교환
const tokenRes = await fetch('https://auth.example.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authorizationCode,
redirect_uri: REDIRECT_URI,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
}),
});
const { access_token, refresh_token } = await tokenRes.json();OAuth2 Reference 소개
OAuth 2.0 레퍼런스는 OAuth 2.0 명세(RFC 6749)와 그 확장에서 정의된 모든 주요 인증 플로우를 다루는 대화형 가이드입니다. Authorization Code Flow(표준 서버 사이드 패턴), PKCE를 포함한 Authorization Code Flow(SPA 및 모바일 앱을 위한 보안 패턴), Client Credentials Flow(머신 간 인증), Device Authorization Flow(TV 및 IoT 디바이스용), 그리고 OAuth 2.0 위에 구축된 OpenID Connect(OIDC) 인증 레이어를 포함합니다. 각 플로우는 단계별 설명, 흐름도, 사용 사례 설명, 복사 가능한 TypeScript/JavaScript 코드 예시와 함께 제공됩니다.
웹 개발자, 모바일 엔지니어, 보안 아키텍트는 Google, GitHub, Auth0, Keycloak, Azure AD 등 외부 Identity Provider에 신원을 위임하는 애플리케이션을 구현할 때 이 레퍼런스를 활용합니다. 올바른 플로우를 선택하는 것이 중요합니다. 현재 폐기된 Implicit Flow처럼 잘못된 플로우를 사용하면 보안 취약점이 생깁니다. 이 레퍼런스는 각 플로우가 작동하는 방식뿐만 아니라 각 단계가 존재하는 이유, 예를 들어 PKCE의 code_verifier/code_challenge 메커니즘이 왜 퍼블릭 클라이언트에서의 인증 코드 인젝션 공격을 방지하는지도 설명합니다.
보안 모범 사례 섹션에서는 안전한 OAuth 2.0 구현을 위한 8가지 핵심 규칙을 다룹니다. state 파라미터로 CSRF 방지, 퍼블릭 클라이언트에 필수적인 PKCE, 모든 통신에 HTTPS 적용, 올바른 토큰 저장 전략(액세스 토큰은 메모리에, 리프레시 토큰은 httpOnly 쿠키에), 스코프 최소화, 정확한 redirect_uri 매칭, Implicit Flow 사용 금지, 액세스 토큰 만료 관리 등입니다. 토큰 관리 섹션에서는 액세스 토큰, 리프레시 토큰, OIDC ID 토큰의 역할과 /revoke 엔드포인트를 통한 토큰 갱신 및 취소 코드를 설명합니다.
주요 기능
- Authorization Code Flow — client_secret을 사용하는 서버 사이드 웹 앱의 표준 패턴
- Authorization Code + PKCE — code_verifier/SHA-256 챌린지를 사용하는 SPA/모바일 앱의 보안 플로우
- Client Credentials Flow — Basic 인증 헤더를 사용한 사용자 컨텍스트 없는 M2M 인증
- Device Authorization Flow — user_code를 통한 스마트 TV/IoT 디바이스용 폴링 기반 인증
- 토큰 관리 — 액세스/리프레시/ID 토큰 생명주기 및 갱신·취소 코드
- OpenID Connect(OIDC) — scope=openid, ID 토큰 JWT 디코딩, userinfo 엔드포인트, OIDC Discovery
- 보안 모범 사례 — CSRF state 파라미터, PKCE, httpOnly 쿠키, 스코프 최소화, Implicit Flow 금지
- 모든 플로우와 개념에 대한 복사 가능한 JavaScript/TypeScript 코드 예시
자주 묻는 질문
OAuth 2.0과 OpenID Connect의 차이는 무엇인가요?
OAuth 2.0은 권한 부여 프레임워크입니다. 애플리케이션이 사용자를 대신하여 리소스에 접근할 권한을 부여하지만, 사용자를 인증하지는 않습니다. OpenID Connect(OIDC)는 OAuth 2.0 위에 구축된 인증 레이어로, sub, name, email 같은 사용자 신원 클레임을 담은 ID 토큰(JWT)을 추가합니다. 사용자가 누구인지 알아야 한다면 OIDC를 사용하고, 단순히 사용자를 대신해 행동하기만 하면 된다면 OAuth 2.0만으로도 충분할 수 있습니다.
PKCE는 언제 사용해야 하고 언제 불필요한가요?
PKCE는 client_secret을 안전하게 저장할 수 없는 모든 퍼블릭 클라이언트, 즉 SPA(React, Vue, Angular), 모바일 앱, 데스크톱 앱에서 필수입니다. client_secret을 기밀로 유지할 수 있는 서버 사이드 웹 앱은 PKCE 없이 표준 Authorization Code Flow를 사용할 수 있습니다. 다만 심층 방어 차원에서 기밀 클라이언트에도 PKCE를 추가하는 것이 점점 권장되고 있습니다.
PKCE의 code_verifier와 code_challenge는 무엇인가요?
code_verifier는 클라이언트가 생성하는 암호학적 무작위 문자열입니다. code_challenge는 code_verifier를 SHA-256으로 해시하고 base64url로 인코딩하여 파생됩니다. 클라이언트는 /authorize 요청에 code_challenge를, /token 요청에 code_verifier를 포함합니다. 인증 서버는 SHA-256(code_verifier)가 저장된 code_challenge와 일치하는지 검증하여 토큰 요청이 인증 플로우를 시작한 동일한 클라이언트에서 온 것임을 확인합니다.
Implicit Flow는 왜 폐기되었나요?
Implicit Flow는 인증 리다이렉트 후 URL 프래그먼트(#access_token=...)에 직접 액세스 토큰을 반환했습니다. 이로 인해 토큰이 브라우저 히스토리, 리퍼러 헤더, 페이지에서 실행되는 JavaScript에 노출되었습니다. 현대적 모범 사례는 URL에 액세스 토큰을 절대 노출하지 않는 PKCE를 포함한 Authorization Code Flow를 사용하는 것입니다.
브라우저 앱에서 액세스 토큰과 리프레시 토큰을 어디에 저장해야 하나요?
액세스 토큰은 메모리(JavaScript 변수나 React 상태)에 저장하세요. 수명이 짧아 페이지 리로드 시 잃어도 감수할 수 있습니다. 리프레시 토큰은 JavaScript로 읽을 수 없고 XSS로부터 보호되는 httpOnly, Secure, SameSite=Strict 쿠키에 저장하세요. 두 토큰 모두 페이지에서 실행되는 모든 JavaScript가 접근할 수 있는 localStorage나 sessionStorage에 저장해서는 안 됩니다.
state 파라미터는 무엇이고 왜 필요한가요?
state 파라미터는 /authorize 리다이렉트 전에 클라이언트가 생성하여 sessionStorage에 저장하는 무작위 값입니다. 인증 서버가 redirect_uri로 다시 리다이렉트한 후, 클라이언트는 URL의 state가 저장된 값과 일치하는지 확인합니다. 이는 공격자가 피해자를 속여 공격자의 인증 코드로 OAuth 플로우를 완료하게 만드는 CSRF 공격을 방지합니다.
Device Authorization Flow는 무엇이고 언제 사용하나요?
Device Authorization Flow(RFC 8628)는 브라우저를 열거나 키보드 입력을 받을 수 없는 디바이스, 즉 스마트 TV, 게임 콘솔, CLI 도구, IoT 디바이스를 위해 설계되었습니다. 디바이스가 인증 서버에서 짧은 user_code를 받아 URL과 함께 표시합니다. 사용자는 스마트폰이나 노트북으로 그 URL을 방문하여 코드를 입력합니다. 한편 디바이스는 사용자가 인증을 완료할 때까지 토큰 엔드포인트를 폴링합니다.
Client Credentials Flow는 Authorization Code Flow와 어떻게 다른가요?
Client Credentials Flow에는 사용자가 없습니다. 애플리케이션 자체가 client_id와 client_secret으로 인증하여 사용자가 아닌 애플리케이션을 나타내는 액세스 토큰을 받습니다. 서비스 간 통신, 백그라운드 작업, 자동화된 시스템에 사용됩니다. Authorization Code Flow는 애플리케이션에 권한을 부여하는 사용자가 개입합니다.