~10 min · auth-security, api-keys, tokens, rotation
Level 0HTTP Newbie
0 XP0/46 lessons0/12 achievements
0/120 XP to next level120 XP to go0% complete
"둘 다 Bearer wire 탐. 차이는 LIFETIME 과 ISSUANCE process. 그 차이가 모든 거 — 보안 자세, rotation 정책, 통합 shape, support 작업량 — 좌우."
같은 wire, 다른 lifecycle
HTTP 관점에서 API key 와 단기 bearer token 이 동일하게 보임 — 둘 다 Authorization: Bearer <string>. 차이가 전부 wire 밖:
API key: 한 번 발급 (수동, dashboard 통해), 장기 (수동 revoke 까지 몇 달에서 몇 년), 보통 통합 당 단일 secret. Server-to-server 가 전형적 fit.
단기 token: 프로그램으로 발급 (login, OAuth flow, exchange), 초에서 시간 안에 expire, refresh 가능. 최종 사용자 세션과 OAuth-grant flow 가 전형적 fit.
맥락에 잘못 고르면 잘못된 보안 자세 만듦.
누설 윈도우 수학
결정이 자주 이거에 옴: 이 자격 증명 새면 얼마나 피해, 피해가 얼마나 지속?
새는 API key: 수동 revoke 까지 유효. Git commit, frontend bundle, 고객-공유 screenshot, CI log 에서 샐 수 있음. 발견-to-revocation 윈도우 며칠 가능. 그 윈도우 동안 공격자가 full 통합 접근.
새는 단기 token: 수명 남은 초 만큼만 유효 — 자주 분. 누설 알아챘을 때 token 이미 무효. Blast radius 가 token TTL 에 한정.
이게 production AI API (Anthropic, OpenAI), payment API (Stripe), 심각한 남용 가능성 가진 API 가 최종 사용자 flow 에 단기 token 의존하는 이유. API key 는 저장 환경 엄밀 통제된 server 쪽 사용에 예약.
API key 가 맞는 도구일 때
API key 가 단순, 견고, 통합 쉬움. Fit 때:
Server-to-server — key 가 통제하는 server 의 환경 변수에 살아. 브라우저 없음, 최종 사용자 없음, 자체 infrastructure 넘는 누설 vector 없음.
Key 당 single tenant — key 가 한 조직이나 service 표현, 한 사람 user 아님.
저빈도 rotation 허용 — 90일 마다 수동 rotation 동작 가능.
안정 identity — 통합이 identity 자주 안 바꿈.
Stripe 의 secret API key (sk_live_...) 가 이 모든 거 fit. Twilio 의 account SID + auth token, Anthropic 의 ANTHROPIC_API_KEY, GitHub 의 personal access token (server 가 사용 시) — 다 server-to-server API key.
단기 token 이 맞는 도구일 때
최종 사용자 세션 — user 가 login, token 받고, 시간 동안 사용, refresh 나 재-login. TTL 가진 브라우저 저장 자격 증명.
OAuth-부여 접근 — 제 3자 앱이 user 대신 행동. User 가 언제든 revoke 가능; 추가 layer 로 token 도 자연 expire.
User 당 scoping 가진 multi-tenant — 각 token 이 특정 user + scope 표현.
모바일이나 SPA 맥락 — 자격 증명이 어느 누설이든 일어날 수 있는 환경에 사는 어디든.
OAuth2 access token, JWT-기반 session token, cwkPippa 의 PIN-발급 bearer token 다 이 패턴 fit.
'구현 쉬운 게 뭐' 아닌 누설 위험으로 선택. API key 가 더 쉬움 — 생성, 복사, 붙여넣기, 완료. 근데 key 가 예상 안 한 곳 (개발자 screenshot, 브라우저 확장, 프로젝트 읽는 AI 도구) 끝나면 결과가 몇 주 노출. Token-기반 flow 가 코드 더 많은데 누설 윈도우 한정. 처음으로 자격 증명 어렵게 잃은 사람이 차이 가르쳐.
Rotation — 잊혀진 절반
API key 와 token 둘 다 rotation 정책 필요:
API key: 통합 당 여러 활성 key 지원 (rotation 이 다운타임 요구 안 함), dashboard 에 key 나이 surface, 90일 rotation 권장, key 당 사용 log (수상한 거 보이면 어느 key revoke 할지 알게).
Token: 짧은 TTL 이 설계상 rotation. Refresh token (긴 TTL, 새 access token mint 에만 사용) 추가하면 재인증 없이 sliding session 얻음.
Stripe 가 secret key 여러 개 동시 활성 허용해서 통합 다운 안 시키고 rotation 가능. JWT-기반 flow 가 단기 access token (~15분) 을 더 긴 refresh token (~30일) 과 분리. 두 패턴; 둘 다 동작.
cwkPippa 의 mix
cwkPippa 가 두 종류 다 운반. 사용자 대면 API 가 단기 bearer token 씀 (PIN login → 24시간 token; refreshable). Brain adapter (Claude, Codex, Gemini, Ollama) 가 .env 에 저장된 장기 API key 씀 — server-to-server, single-tenant, env 파일이 Mac 안 떠나서 저 rotation 위험. 두 패턴 공존 — 누설 면 다름: user token 누설이 한 세션 compromise; Anthropic API key 누설이 알아챌 때까지 실제 청구 올림. 보호가 위험 매칭.
Code
한 endpoint, 두 자격 증명 type — 둘 다 Bearer scheme 통해·python
# Server 쪽 — 한 endpoint 에 장기 API key 와 단기 token 둘 다 받음
from fastapi import FastAPI, Depends, HTTPException, status, Header
from typing import Annotated
app = FastAPI()
# 가상 store; production: DB + Redis
_api_keys: set[str] = {'sk_live_abc123_owned_by_org_xyz'}
_active_tokens: dict[str, str] = {'tok_short_lived_xyz': 'u_42'}
async def authenticate(
authorization: Annotated[str | None, Header()] = None,
) -> dict:
if not authorization or not authorization.startswith('Bearer '):
raise HTTPException(401, detail='Bearer 필수',
headers={'WWW-Authenticate': 'Bearer'})
credential = authorization.removeprefix('Bearer ').strip()
# API key 먼저 시도 (장기, server-to-server)
if credential in _api_keys:
return {'kind': 'api_key', 'identity': 'org_xyz'}
# 단기 token 으로 fallback (user 세션)
if credential in _active_tokens:
return {'kind': 'session_token', 'identity': _active_tokens[credential]}
raise HTTPException(401, detail='알 수 없는 자격 증명',
headers={'WWW-Authenticate': 'Bearer'})
@app.get('/account')
async def me(auth = Depends(authenticate)):
return auth
이전 lesson 의 FastAPI auth 를 장기 API key (시작시 환경 변수에서 읽음) 와 단기 session token (15분 expiry 가진 /login endpoint 발급 + 갱신 위한 /refresh endpoint) 둘 다 지원하게 확장. 같은 Authorization: Bearer ... header 가 둘 다에 동작해야. 테스트 시나리오: (1) 성공 API key 접근, (2) 성공 단기 token 접근, (3) 만료된 단기 token 접근 (401 해야), (4) 재-login 없이 접근 복원하는 refresh flow. 보너스: 각 request 에 어느 자격 증명 type 썼는지 log, 미래의 너가 트래픽 패턴 audit 가능.
Hint
Dispatch 단순: API key set 먼저 시도 (장기); 못 찾으면 token store (expiry check 가진 단기) 시도; 아니면 401. Refresh endpoint 가 refresh token 받고 신선한 access token 발급 — refresh token 자체는 장기인데 /refresh 에서만 사용 가능 (API 접근엔 아님), 누설 blast radius 제한. 자격 증명 type 로깅 이 user 가 어찌어찌 브라우저 맥락에서 server API key 쓰는 거 찾아주는데, 일찍 잡고 싶은 misconfiguration.
Progress
Progress is local-only — sign in to sync across devices.