API 키는 클라이언트(주로 서버·스크립트·SDK)를 식별하는 긴 무작위 문자열로, 보통 `X-API-Key`나 `Authorization` 헤더에 실어 보냅니다. 사용자 신원보다는 '어떤 애플리케이션·프로젝트의 호출인가'를 구분하고, 쿼터·요금·rate limit을 매기는 데 초점이 있습니다.
Header (e.g. X-API-Key: <key>) / query param / cookie발급된 키 하나가 곧 자격 증명이므로 소지자가 권한을 갖는다는 점에서 Bearer 토큰과 성격이 비슷합니다. 다만 만료가 없거나 매우 길고, 사람이 아니라 프로그램(서버 간 통신, 결제 게이트웨이, 지도·번역 API 등)이 쓰는 경우가 많습니다. 서버는 키를 받아 저장소에서 조회하고 소유자·스코프·rate limit·폐기 여부를 확인합니다.
좋은 설계는 키에 prefix(예: `sk_live_`, `pk_test_`)를 붙여 종류·환경을 눈으로 구분하게 하고, 원문 대신 해시만 저장하며(유출 시 원문 복원 불가), 키마다 스코프(권한 범위)와 사용량 제한을 부여합니다. 초과 시 429 Too Many Requests로 응답합니다.
가장 흔한 실수는 키를 URL 쿼리스트링(`?api_key=...`)에 넣는 것입니다. URL은 서버 접근 로그·프록시·브라우저 히스토리·Referer 헤더·CDN 캐시에 그대로 남기 때문에, 키는 반드시 헤더로 보내야 합니다.
X-API-Key: sk_live_51H8xq2eZvKYlo2C0abcd1234efgh5678curl -H 'X-API-Key: sk_live_...' https://api.example.com/v1/datafetch('/v1/data', {
headers: { 'X-API-Key': process.env.API_KEY }
});key = request.headers.get('X-API-Key', '')
record = db.api_keys.find_by_hash(sha256(key)) # store only hashes
if not record or record.revoked:
abort(401)
if not record.scopes.allows(request.path):
abort(403)