본문 바로가기
C.W.K.
Stream
Lesson 02 of 04 · published

토큰 갱신과 loadCodeAssist

~14 min · oauth, refresh-token, load-code-assist

Level 0불씨
0 XP0/35 lessons0/10 achievements
0/140 XP to next level140 XP to go0% complete

OAuth 갱신 흐름

표준 Google OAuth에서 액세스 토큰은 약 1시간 동안 유효해. 그 뒤에는 갱신 토큰을 oauth2.googleapis.com/token에 grant_type=refresh_token으로 POST해 새 액세스 토큰을 받아. 새 만료 시간을 저장하고 토큰이 죽기 전에 교체해.

loadCodeAssist — 건너뛸 수 없는 사전 호출

OAuth 경로에서 첫 생성 요청을 보내기 전에 반드시 loadCodeAssist를 호출해야 해. 이 호출은 이후 모든 generateContent 본문의 project 필드에 넣을 cloudaicompanionProject 문자열을 반환해. 건너뛰면 헷갈리는 오류 메시지와 함께 HTTP 500을 받아.

OAuth 클라이언트 자격 증명은 공개돼 있어

Gemini CLI는 client_id와 client_secret을 코드에 넣어 배포해. CLI를 쓰는 누구나 같은 쌍을 사용하므로 공개 정보야. Google도 비밀이 아니라 식별자로 다뤄. 자체 OAuth 흐름에서도 쓸 수 있어.

Code

액세스 토큰 갱신·python
import json, os, time, requests

# Public — same values the Gemini CLI uses
GEMINI_CLI_CLIENT_ID     = '681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com'
GEMINI_CLI_CLIENT_SECRET = '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'

CREDS_PATH = os.path.expanduser('~/.gemini/oauth_creds.json')

def get_access_token():
    with open(CREDS_PATH) as f:
        creds = json.load(f)

    # Refresh if expired (or about to)
    if creds.get('expiry_date', 0) < (time.time() + 60) * 1000:
        resp = requests.post('https://oauth2.googleapis.com/token', data={
            'client_id':     GEMINI_CLI_CLIENT_ID,
            'client_secret': GEMINI_CLI_CLIENT_SECRET,
            'refresh_token': creds['refresh_token'],
            'grant_type':    'refresh_token',
        })
        resp.raise_for_status()
        new = resp.json()
        creds['access_token'] = new['access_token']
        creds['expiry_date']  = int(time.time() * 1000) + new['expires_in'] * 1000
        with open(CREDS_PATH, 'w') as f:
            json.dump(creds, f)

    return creds['access_token']
loadCodeAssist — project 문자열 받기·python
import requests

def load_code_assist(access_token):
    resp = requests.post(
        'https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist',
        headers={
            'Authorization': f'Bearer {access_token}',
            'Content-Type': 'application/json',
        },
        json={
            'cloudaicompanionProject': '',
            'metadata': {
                'ideType':    'IDE_UNSPECIFIED',
                'platform':   'PLATFORM_UNSPECIFIED',
                'pluginType': 'GEMINI',
            },
        },
    )
    resp.raise_for_status()
    return resp.json().get('cloudaicompanionProject')
합치기 — OAuth 인증 호출 시작하기·python
token   = get_access_token()
project = load_code_assist(token)  # cache this — usually stable per-user

resp = requests.post(
    'https://cloudcode-pa.googleapis.com/v1internal:generateContent',
    headers={
        'Authorization': f'Bearer {token}',
        'Content-Type':  'application/json',
    },
    json={
        'model':   'gemini-2.5-flash',
        'project': project,
        'request': {
            'contents': [{'role': 'user', 'parts': [{'text': 'Hello'}]}],
            'generationConfig': {},
        },
    },
)
print(resp.json()['response']['candidates'][0]['content']['parts'][0]['text'])

External links

Exercise

작은 Python 스크립트에서 get_access_token()load_code_assist()를 처음부터 구현해. 직접 가진 ~/.gemini/oauth_creds.json을 사용하고, 갱신이 작동하는지, loadCodeAssist가 project를 반환하는지, 직접 보낸 v1internal:generateContent POST가 텍스트를 반환하는지 확인해. Gemini CLI를 설치하지 않았다면 새 client_secrets 파일에서 OAuth 흐름을 작성해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.