Google Colab에서 YouTube API OAuth 인증 문제 해결하기

신영·2026년 3월 20일

Troubleshooting

목록 보기
3/3
post-thumbnail

목차
🚨 문제 상황
🔍 문제 원인 분석
💡 해결방법: Manual OAuth Flow
🛠️ 설정 가이드
🔍 동작 원리 심화 이해
🎯 핵심 포인트 정리
📚 참고 자료

🚨 문제 상황

Google Colab에서 YouTube Data API를 사용해 비디오에 좋아요/싫어요를 하는 샘플 코드(https://github.com/youtube/api-samples/blob/master/python/like_video.py) 테스트를 시도하다가 다음과 같은 문제들에 직면했습니다.

발생한 오류들

1. OAuth 방식 선택 시

localhost에서 연결을 거부했습니다.

2. Colab 내장 인증 사용 시

WARNING:googleapiclient.http:Encountered 403 Forbidden with reason "insufficientPermissions"

❌ HTTP Error 403: Request had insufficient authentication scopes.

🔍 문제 원인 분석

1. localhost 연결 거부의 원인

기존에 사용하던 일반적인 OAuth 인증 코드는 다음과 같았습니다:

from google_auth_oauthlib.flow import InstalledAppFlow

flow = InstalledAppFlow.from_client_secrets_file(client_secrets_file, SCOPES)
credentials = flow.run_local_server(port=0, open_browser=False)

실패 원인

  • run_local_server(): 로컬에서 HTTP 서버를 실행하려 시도
  • Google Colab의 제약: 샌드박스 환경으로 임의 포트 바인딩 불가
  • 네트워크 격리: 외부에서 localhost 접근 차단

2. 권한 부족 오류의 원인

from google.colab import auth
auth.authenticate_user()
Colab 내장 인증을 사용했지만 403 오류가 발생했습니다.

에러 원인

  • 기본 스코프 제한: Colab 인증은 기본적으로 제한된 권한만 제공
  • YouTube API 특성: YouTube Data API는 특별한 OAuth 스코프 필요
  • 서비스 계정 미지원: YouTube API는 OAuth만 지원, 서비스 계정 불가

💡 해결방법: Manual OAuth Flow

OAuth 2.0 인증 방식의 이해

OAuth에는 여러 인증 방식이 있습니다.

방식Redirect URI사용 환경Colab 지원
웹 애플리케이션http://example.com/callback웹서버
데스크톱 앱http://localhost:PORT로컬 환경
Manual/OOBurn:ietf:wg:oauth:2.0:oob제한된 환경

핵심은 urn:ietf:wg:oauth:2.0:oob (Out-of-Band) 방식을 사용하는 것입니다.

해결 코드

import os
import json
import requests
from urllib.parse import urlencode
from google.colab import files
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials

# OAuth 설정
GOOGLE_AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth'
GOOGLE_TOKEN_URL = 'https://oauth2.googleapis.com/token'
SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl']

def load_client_secrets():
    """OAuth 클라이언트 시크릿 파일 로드"""
    print("📁 OAuth client secrets JSON 파일을 업로드해주세요:")
    uploaded = files.upload()
    
    if not uploaded:
        raise Exception("파일이 업로드되지 않았습니다.")
    
    client_secrets_file = list(uploaded.keys())[0]
    
    with open(client_secrets_file, 'r') as f:
        client_secrets = json.load(f)
    
    # 클라이언트 정보 추출
    if 'installed' in client_secrets:
        client_info = client_secrets['installed']
    elif 'web' in client_secrets:
        client_info = client_secrets['web']
    else:
        raise Exception("올바르지 않은 클라이언트 시크릿 형식입니다.")
    
    return {
        'client_id': client_info['client_id'],
        'client_secret': client_info['client_secret']
    }

def get_oauth_credentials():
    """Manual OAuth 인증 수행"""
    
    # 클라이언트 정보 로드
    client_info = load_client_secrets()
    client_id = client_info['client_id']
    client_secret = client_info['client_secret']
    
    # Step 1: 인증 URL 생성
    auth_params = {
        'client_id': client_id,
        'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob',  # 🔑 핵심!
        'scope': ' '.join(SCOPES),
        'response_type': 'code',
        'access_type': 'offline',
        'prompt': 'consent'
    }
    
    auth_url = f"{GOOGLE_AUTH_URL}?{urlencode(auth_params)}"
    
    # Step 2: 사용자 인증 안내
    print("\n" + "="*60)
    print("🌐 다음 URL을 새 브라우저 탭에서 열어주세요:")
    print("="*60)
    print(auth_url)
    print("="*60)
    
    print("\n📋 인증 절차:")
    print("1. 위 URL을 클릭하거나 복사해서 브라우저에서 열기")
    print("2. Google 계정으로 로그인")
    print("3. 애플리케이션 권한 승인")
    print("4. 나타나는 인증 코드를 복사")
    print("5. 아래에 붙여넣기")
    
    # Step 3: 인증 코드 입력받기
    auth_code = input("\n🔑 인증 코드를 입력하세요: ").strip()
    
    if not auth_code:
        raise Exception("인증 코드가 입력되지 않았습니다.")
    
    # Step 4: 액세스 토큰으로 교환
    print("\n🔄 인증 코드를 액세스 토큰으로 교환 중...")
    
    token_data = {
        'client_id': client_id,
        'client_secret': client_secret,
        'code': auth_code,
        'grant_type': 'authorization_code',
        'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob'
    }
    
    response = requests.post(GOOGLE_TOKEN_URL, data=token_data)
    
    if response.status_code != 200:
        raise Exception(f"토큰 교환 실패: {response.text}")
    
    token_info = response.json()
    
    if 'error' in token_info:
        raise Exception(f"OAuth 오류: {token_info['error_description']}")
    
    # Step 5: Credentials 객체 생성
    credentials = Credentials(
        token=token_info['access_token'],
        refresh_token=token_info.get('refresh_token'),
        token_uri=GOOGLE_TOKEN_URL,
        client_id=client_id,
        client_secret=client_secret,
        scopes=SCOPES
    )
    
    print("✅ 인증 완료!")
    return build('youtube', 'v3', credentials=credentials)

def rate_video(youtube_service, video_id, rating):
    """YouTube 비디오 평가하기"""
    try:
        youtube_service.videos().rate(
            id=video_id,
            rating=rating
        ).execute()
        
        print(f"✅ '{rating}' 평가가 비디오 {video_id}에 적용되었습니다!")
        
    except Exception as e:
        print(f"❌ 오류 발생: {e}")
        raise

# 사용 예시
def main():
    print("🎥 YouTube 비디오 평가하기")
    
    try:
        # 인증
        youtube = get_oauth_credentials()
        
        # 비디오 ID 입력
        video_id = input("\n📹 YouTube 비디오 ID를 입력하세요: ").strip()
        
        # 평가 선택
        rating = input("평가를 선택하세요 (like/dislike/none): ").strip().lower()
        
        if rating not in ['like', 'dislike', 'none']:
            print("❌ 잘못된 평가입니다.")
            return
        
        # 평가 적용
        rate_video(youtube, video_id, rating)
        
    except Exception as e:
        print(f"❌ 오류: {e}")

if __name__ == '__main__':
    main()

🛠️ 설정 가이드

1. Google Cloud Console 설정

Step 1: 프로젝트 생성

  1. Google Cloud Console 접속
  2. 새 프로젝트 생성 또는 기존 프로젝트 선택

Step 2: YouTube Data API 활성화

  1. 좌측 메뉴에서 "APIs & Services" → "Library" 선택
  2. "YouTube Data API v3" 검색
  3. API 활성화

Step 3: OAuth 2.0 클라이언트 ID 생성

  1. "APIs & Services" → "Credentials" 선택
  2. "CREATE CREDENTIALS" → "OAuth 2.0 Client ID" 클릭
  3. Application type: "Desktop Application" 선택
  4. 이름 입력 후 생성
  5. JSON 파일 다운로드

2. Colab에서 실행

  1. 위 코드를 Colab 셀에 복사
  2. main() 함수 실행
  3. OAuth JSON 파일 업로드
  4. 인증 URL 방문하여 권한 승인
  5. 인증 코드 복사 후 입력
  6. 비디오 ID와 평가 입력

🔍 동작 원리 심화 이해

Manual OAuth Flow의 작동 과정

1. 애플리케이션 → Google OAuth 서버
   "인증 URL 생성 요청"
   
   GET https://accounts.google.com/o/oauth2/v2/auth?
       client_id=YOUR_CLIENT_ID&
       redirect_uri=urn:ietf:wg:oauth:2.0:oob&
       scope=https://www.googleapis.com/auth/youtube.force-ssl&
       response_type=code&
       access_type=offline

2. 사용자 → 브라우저
   "인증 URL 방문 및 Google 로그인"
   
3. Google → 사용자
   "권한 승인 화면 표시"
   
4. 사용자 → Google
   "권한 승인"
   
5. Google → 사용자 (브라우저)
   "인증 코드를 화면에 표시"
   (일반적인 redirect 대신!)
   
6. 사용자 → 애플리케이션
   "인증 코드 수동 입력"
   
7. 애플리케이션 → Google OAuth 서버
   "인증 코드를 액세스 토큰으로 교환"
   
   POST https://oauth2.googleapis.com/token
   Content-Type: application/x-www-form-urlencoded
   
   client_id=YOUR_CLIENT_ID&
   client_secret=YOUR_CLIENT_SECRET&
   code=AUTHORIZATION_CODE&
   grant_type=authorization_code&
   redirect_uri=urn:ietf:wg:oauth:2.0:oob

8. Google → 애플리케이션
   "액세스 토큰 및 리프레시 토큰 반환"
   
   {
     "access_token": "ya29.a0AfH6SMCX...",
     "refresh_token": "1//04-rNHF5pI...",
     "token_type": "Bearer",
     "expires_in": 3599
   }

9. 애플리케이션 → YouTube API
   "액세스 토큰으로 API 호출"

urn:ietf:wg:oauth:2.0:oob의 의미

  • OOB: "Out-of-Band"의 약자
  • 의미: 일반적인 HTTP 리다이렉트 대신 브라우저 화면에 직접 인증 코드 표시
  • 사용 시나리오:
    • 로컬 서버를 실행할 수 없는 환경
    • 모바일 앱이나 데스크톱 앱
    • 제한된 네트워크 환경 (Colab 등)

이 방법이 Colab에서 작동하는 이유

기존 방식의 문제점:

# ❌ Colab에서 불가능한 작업들
import socket
socket.bind(('localhost', 8080))  # 포트 바인딩 제한

import webbrowser  
webbrowser.open(url)  # 브라우저 제어 불가

from http.server import HTTPServer
server = HTTPServer(...)  # HTTP 서버 실행 불가

해결된 방식의 장점:

# ✅ Colab에서 가능한 작업들
import requests
requests.post(url, data=data)  # HTTP 클라이언트 요청

user_input = input("입력: ")  # 사용자 입력 받기
print("URL:", auth_url)       # 텍스트 출력

🎯 핵심 포인트 정리

1. 환경별 제약 이해

  • 로컬 개발환경: 대부분의 OAuth 방식 지원
  • Google Colab: 샌드박스 환경으로 네트워크 제약
  • 클라우드 환경: 각 플랫폼별 고유 제약 존재

2. OAuth 방식 선택의 중요성

환경추천 방식이유
로컬 PCrun_local_server()가장 편리함
ColabManual OOB네트워크 제약 우회
서버 환경Service Account자동화에 적합 (YouTube API는 제외)

3. 문제 해결 접근법

  1. 에러 메시지 정확한 분석: "localhost 연결 거부" = 네트워크 제약
  2. 환경 특성 파악: Colab = 샌드박스 환경
  3. 대안 방법 탐색: OAuth 표준 내에서 다른 플로우 찾기
  4. 저수준 구현: 라이브러리가 안 되면 직접 HTTP 요청

📚 참고 자료


혹시 다른 문제가 생기거나 궁금한 점이 있다면 언제든 댓글로 남겨주세요!

profile
Human×Tech Bridge Builder | EdTech | AI Service Developer

0개의 댓글