OAuth 2.0 인증

ONDA API 인증 체계와 토큰 관리 방법을 안내합니다.

OAuth 2.0 인증

ONDA API는 OAuth 2.0 프로토콜을 사용하여 안전한 인증을 제공합니다. API 호출 시 모든 요청에 Access Token을 포함해야 합니다.

OAuth 2.0 개요

OAuth 2.0은 산업 표준 인증 프로토콜로, 사용자 비밀번호를 직접 공유하지 않고도 안전하게 API 접근 권한을 위임할 수 있습니다.

Interactive demo — use the portal console

ONDA API는 두 가지 OAuth 플로우를 지원합니다:

플로우사용 케이스보안 수준
Client Credentials서버-투-서버 통신 (백엔드)높음
Authorization Code + PKCE사용자 인증이 필요한 경우 (프론트엔드)매우 높음

Client Credentials 플로우

서버-투-서버 통신에 적합한 플로우입니다. 대부분의 채널 파트너가 사용합니다.

1. Access Token 발급

Client Credentials 플로우

요청 파라미터:

파라미터필수설명
grant_typeclient_credentials 고정
client_id채널 생성 시 발급받은 Client ID
client_secret채널 생성 시 발급받은 Client Secret
scope요청 권한 범위 (기본값: read write)

응답:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjaGFubmVsXzEyMzQ1NiIsImlhdCI6MTcwOTM3MDAwMCwiZXhwIjoxNzA5MzcwOTAwLCJzY29wZSI6InJlYWQgd3JpdGUifQ...",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_token": "rt_abc123def456",
  "scope": "read write"
}

2. API 호출

발급받은 Access Token을 Authorization 헤더에 포함하여 API를 호출합니다.

API 호출 예시

Authorization Code + PKCE 플로우

사용자 인증이 필요한 경우 사용하는 플로우입니다. PKCE(Proof Key for Code Exchange)를 사용하여 보안을 강화합니다.

1. Authorization URL 생성

import secrets
import hashlib
import base64

# Code Verifier 생성 (43-128자의 랜덤 문자열)
code_verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).decode('utf-8').rstrip('=')

# Code Challenge 생성 (SHA256 해시)
code_challenge = base64.urlsafe_b64encode(
    hashlib.sha256(code_verifier.encode('utf-8')).digest()
).decode('utf-8').rstrip('=')

# Authorization URL
auth_url = (
    "https://api.onda.me/v1/oauth/authorize"
    f"?client_id=YOUR_CLIENT_ID"
    f"&redirect_uri=https://your-app.com/callback"
    f"&response_type=code"
    f"&scope=read write"
    f"&code_challenge={code_challenge}"
    f"&code_challenge_method=S256"
)

# 사용자를 이 URL로 리다이렉트
print(f"Redirect to: {auth_url}")

2. Authorization Code로 토큰 교환

사용자가 인증을 완료하면 redirect_uri로 Authorization Code가 전달됩니다.

import requests

# redirect_uri로 전달된 code 파라미터
authorization_code = "ac_xyz789"

response = requests.post(
    "https://api.onda.me/v1/oauth/token",
    data={
        "grant_type": "authorization_code",
        "client_id": "YOUR_CLIENT_ID",
        "code": authorization_code,
        "redirect_uri": "https://your-app.com/callback",
        "code_verifier": code_verifier,  # 1단계에서 생성한 값
    },
)

token_data = response.json()
access_token = token_data["access_token"]
refresh_token = token_data["refresh_token"]

토큰 라이프사이클

Access Token

  • 유효 기간: 15분 (900초)
  • 용도: API 호출 인증
  • 저장 위치: 메모리 (권장) 또는 안전한 스토리지

Refresh Token

  • 유효 기간: 30일
  • 용도: Access Token 갱신
  • 저장 위치: 암호화된 데이터베이스 또는 Secure Storage

Refresh Token은 절대 클라이언트 측(브라우저)에 저장하지 마세요. 서버에서만 관리해야 합니다.

토큰 갱신

Access Token이 만료되기 전에 Refresh Token을 사용하여 갱신합니다.

토큰 갱신

자동 갱신 구현 예시

import time
import requests

class TokenManager:
    def __init__(self, client_id, client_secret):
        self.client_id = client_id
        self.client_secret = client_secret
        self.access_token = None
        self.refresh_token = None
        self.expires_at = 0

    def get_token(self):
        """현재 유효한 토큰 반환 (필요시 자동 갱신)"""
        if time.time() >= self.expires_at - 60:  # 만료 1분 전에 갱신
            self._refresh_token()
        return self.access_token

    def _refresh_token(self):
        """토큰 갱신"""
        response = requests.post(
            "https://api.onda.me/v1/oauth/token",
            data={
                "grant_type": "refresh_token" if self.refresh_token else "client_credentials",
                "refresh_token": self.refresh_token,
                "client_id": self.client_id,
                "client_secret": self.client_secret,
            },
        )
        data = response.json()
        self.access_token = data["access_token"]
        self.refresh_token = data["refresh_token"]
        self.expires_at = time.time() + data["expires_in"]

보안 가이드라인

Client Secret 보호

절대 금지: Client Secret을 클라이언트 측 코드(JavaScript, 모바일 앱 등)에 포함하지 마세요.

올바른 방법:

  • 서버 환경 변수에 저장
  • AWS Secrets Manager, HashiCorp Vault 등 사용
  • .env 파일 사용 시 .gitignore에 추가

잘못된 방법:

  • Git 저장소에 커밋
  • 브라우저 JavaScript에 노출
  • 모바일 앱 코드에 하드코딩

Token 저장

토큰 유형서버브라우저모바일 앱
Access Token메모리 또는 Redis메모리Keychain/Keystore
Refresh Token암호화된 DB❌ 저장 금지Secure Storage
Client Secret환경 변수❌ 저장 금지❌ 저장 금지

HTTPS 필수

모든 API 호출은 HTTPS를 통해서만 가능합니다. HTTP 요청은 자동으로 거부됩니다.

IP 화이트리스트

파트너 센터에서 허용할 IP 주소를 등록하여 추가 보안을 적용할 수 있습니다.

에러 코드

401 Unauthorized

{
  "error": "invalid_token",
  "error_description": "The access token is invalid or has expired"
}

원인: 토큰이 만료되었거나 유효하지 않음 해결: 토큰을 재발급하거나 갱신

403 Forbidden

{
  "error": "insufficient_scope",
  "error_description": "The request requires higher privileges than provided by the access token"
}

원인: 토큰의 scope가 부족함 해결: 필요한 scope를 포함하여 토큰을 재발급

400 Bad Request (Invalid Grant)

{
  "error": "invalid_grant",
  "error_description": "The provided refresh token is invalid, expired, or revoked"
}

원인: Refresh Token이 만료되었거나 무효화됨 해결: Client Credentials 플로우로 새 토큰 발급

다음 단계