전체 그래프
Authentication

OAuth

web-securityauthenticationoauthauthorization

상위: Web Security

요약

OAuth 2.0은 제3자 애플리케이션이 사용자의 리소스에 접근할 수 있도록 권한을 위임하는 프로토콜입니다. "Google로 로그인", "카카오로 로그인" 등의 소셜 로그인에 사용됩니다.

핵심 개념

OAuth의 목적

 비밀번호 공유 없이
 제한된 접근 권한 부여

예시:

  • "이 앱이 내 Google 캘린더를 읽을 수 있게 허용"
  • "이 앱이 내 카카오톡 프로필을 볼 수 있게 허용"

4가지 역할

역할설명예시
Resource Owner리소스 소유자 (사용자)당신
Client접근을 요청하는 앱새로운 앱
Authorization Server인증 서버Google 로그인 서버
Resource Server리소스 보유 서버Google API 서버

Authorization Code Grant (가장 일반적)

┌─────────┐                                  ┌─────────────────┐
  User                                       Authorization  
(Browser)                                       Server      
└────┬────┘                                      (Google)     
                                            └────────┬────────┘
       1. 로그인 버튼 클릭                            
     │─────────────────────────────────────▶│        
                                                    
       2. Google 로그인 페이지로 리다이렉트            
     │◀─────────────────────────────────────│        
                                                    
       3. 사용자 로그인  권한 동의                   
     │─────────────────────────────────────▶│        
                                                    
       4. Authorization Code와 함께 리다이렉트         
     │◀─────────────────────────────────────│        
                                                    
                         ┌──────────┐               
                           Client                 
                          (Server)                
                         └────┬─────┘               
                                                   
       5. Code를 서버로 전달                        
     │────────────────────────▶│                     
                                                   
                                6. Code + Client Secret으로 Token 교환
                              │────────────────────────────────▶│
                                                               
                                7. Access Token 반환           
                              │◀────────────────────────────────│
                                                               
       8. 로그인 완료                                          
     │◀────────────────────────│                                 

단계별 상세

1-2. 인증 요청

https://accounts.google.com/oauth/authorize?
  client_id=YOUR_CLIENT_ID&
  redirect_uri=https://yourapp.com/callback&
  response_type=code&
  scope=email profile&
  state=random_string  # CSRF 방지

3-4. 사용자 동의 후 리다이렉트

https://yourapp.com/callback?
  code=AUTHORIZATION_CODE&
  state=random_string

5-7. 토큰 교환 (서버 간 통신)

POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=AUTHORIZATION_CODE&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET&
redirect_uri=https://yourapp.com/callback

응답:

{
  "access_token": "ya29.xxx...",
  "refresh_token": "1//xxx...",
  "expires_in": 3600,
  "token_type": "Bearer"
}

OAuth vs OpenID Connect

항목OAuth 2.0OpenID Connect (OIDC)
목적권한 부여 (Authorization)인증 (Authentication)
반환 값Access TokenAccess Token + ID Token
용도"앱이 내 데이터 접근""이 사람이 누구인가"
표준권한만신원 정보 포함

OIDC ID Token 예시

{
  "iss": "https://accounts.google.com",
  "sub": "1234567890",
  "email": "[email protected]",
  "name": "홍길동",
  "picture": "https://...",
  "iat": 1234567890,
  "exp": 1234571490
}

토큰 종류

토큰용도수명
Access TokenAPI 접근짧음 (1시간)
Refresh TokenAccess Token 갱신김 (수개월)
ID Token사용자 정보짧음

토큰 갱신

POST https://oauth2.googleapis.com/token

grant_type=refresh_token&
refresh_token=REFRESH_TOKEN&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET

OAuth Grant Types

Grant Type용도보안
Authorization Code웹 앱, 서버 사이드높음
Authorization Code + PKCE모바일, SPA높음
Implicit (deprecated)SPA (구식)낮음
Client Credentials서버 간 통신중간
Resource Owner Password자사 앱만낮음

PKCE (Proof Key for Code Exchange)

모바일/SPA에서 Client Secret 없이 안전하게

// 1. Code Verifier 생성 (랜덤 문자열)
const codeVerifier = generateRandomString(64);

// 2. Code Challenge 생성 (SHA-256 해시)
const codeChallenge = base64UrlEncode(sha256(codeVerifier));

// 3. 인증 요청에 포함
// code_challenge=xxxxx&code_challenge_method=S256

// 4. 토큰 교환 시 code_verifier 전송
// code_verifier=original_verifier

보안 취약점

1. CSRF 공격

공격자가 자신의 Authorization Code를 피해자에게 사용하게 유도
 피해자 계정이 공격자 계정에 연결됨

방어: state 파라미터 사용

# 요청 
state = generate_random_string()
session['oauth_state'] = state

# 콜백에서 검증
if request.args['state'] != session['oauth_state']:
    abort(403, "CSRF attack detected")

2. Open Redirect

공격자가 redirect_uri를 조작
 Authorization Code가 공격자에게 전송

방어: redirect_uri 화이트리스트

ALLOWED_REDIRECTS = ['https://myapp.com/callback']

if redirect_uri not in ALLOWED_REDIRECTS:
    abort(400, "Invalid redirect_uri")

3. Authorization Code 탈취

Code가 URL에 노출되어 Referer 헤더나 로그로 유출

방어:

  • Code는 1회용 + 짧은 유효시간 (10분)
  • PKCE 사용
  • HTTPS 필수

4. Access Token 노출

Token이 프론트엔드 코드나 로그에 노출

방어:

  • Token은 메모리에만 저장 (localStorage 금지)
  • 백엔드에서 토큰 관리
  • 짧은 만료 시간

구현 예시

Python (Flask + Google)

from flask import Flask, redirect, request, session
import requests

app = Flask(__name__)
app.secret_key = 'your-secret-key'

CLIENT_ID = 'your-client-id'
CLIENT_SECRET = 'your-client-secret'
REDIRECT_URI = 'http://localhost:5000/callback'

@app.route('/login')
def login():
    state = secrets.token_urlsafe(16)
    session['oauth_state'] = state

    return redirect(
        f"https://accounts.google.com/o/oauth2/auth?"
        f"client_id={CLIENT_ID}&"
        f"redirect_uri={REDIRECT_URI}&"
        f"response_type=code&"
        f"scope=email profile&"
        f"state={state}"
    )

@app.route('/callback')
def callback():
    # CSRF 검증
    if request.args['state'] != session.get('oauth_state'):
        return "CSRF detected", 403

    code = request.args['code']

    # 토큰 교환
    token_response = requests.post(
        'https://oauth2.googleapis.com/token',
        data={
            'code': code,
            'client_id': CLIENT_ID,
            'client_secret': CLIENT_SECRET,
            'redirect_uri': REDIRECT_URI,
            'grant_type': 'authorization_code'
        }
    )

    tokens = token_response.json()
    access_token = tokens['access_token']

    # 사용자 정보 조회
    user_info = requests.get(
        'https://www.googleapis.com/oauth2/v2/userinfo',
        headers={'Authorization': f'Bearer {access_token}'}
    ).json()

    return f"Hello, {user_info['name']}!"

주요 OAuth 제공자

제공자문서
Googledevelopers.google.com/identity
Kakaodevelopers.kakao.com
Naverdevelopers.naver.com
GitHubdocs.github.com/oauth

관련 개념

  • JWT - Access Token 형식으로 자주 사용
  • Session - 전통적 인증 방식
  • CORS - Cross-Origin 요청 제어
  • CSRF - OAuth 보안 위협

참고 자료