AIREITER

AI 이미지

FLUX.2 ProGPT-Image 2Wan 2.7 Image ProGPT 4o ImageSeedream 5.0 ProSeedream V5 liteSeedream V4.5더 보기

AI 비디오

Kling 3.0 Motion ControlSora 2 ProKling 3.0 TurboSora 2Kling 3.0Grok Imagine 1.5Veo 3.1더 보기

LLM

Gemini 3.6 FlashGemini 3.1 ProKimi K3Gemini 3 ProGemini 2.5 ProClaude Opus 5Claude Fable 5더 보기
곧 출시Seedance 2.5
Super ResolutionLyric Video GeneratorGPT Image 2 1K GeneratorGPT Image 2 Product Mockup GeneratorUse GPT-5.6 Online
API 문서가격
블로그업데이트LLM API GuideClaude API GuideKimi K3 API Guide
템플릿
  • AIReiter
  • 블로그
  • Invalid API Key: 고치기 전에 401과 403부터 구분하기

Invalid API Key: 고치기 전에 401과 403부터 구분하기

마지막 업데이트: 2026-07-31 08:40:01

401은 서버가 자격 증명을 거부했다는 뜻이지, API 키 문자열 자체가 틀렸다는 뜻은 아니다. 403 역시 반드시 권한 부족을 의미하지는 않는다. 두 제공업체 모두 키가 완전히 유효한 상황에서도 이 상태 코드를 반환할 수 있다. 다만 가장 먼저 확인할 예외가 하나 있다. 오류 응답에 마스킹되어 표시된 키의 앞뒤 문자가 내가 가진 키와 다르다면, 서버까지 전달된 자격 증명은 의도했던 키가 아니다.

겉으로는 똑같은 401, 원인은 세 가지

아래 세 경우는 모두 인증 오류 유형의 HTTP 401을 반환하지만, 해결 방법은 서로 정반대다. 메시지는 의도적으로 잘못된 키로 두 엔드포인트에 각각 세 번씩 요청해 받은 결과다. 잘못된 자격 증명은 인가 단계 전에 거부되므로 실제 키 없이도 재현할 수 있다.

실제로 일어난 일Anthropic /v1/messagesOpenAI /v1/responses
키가 전달됐지만 거부됨API key is invalid.Incorrect API key provided: sk-proj-**********-key., "code": "invalid_api_key"
자격 증명이 전혀 도착하지 않음x-api-key header is requiredMissing bearer or basic authentication in header
자격 증명을 잘못된 헤더로 보냄Invalid bearer tokenMissing bearer or basic authentication in header — 바로 윗행과 동일

Anthropic은 세 상황을 각각 구분해 알려 준다. 반면 OpenAI 엔드포인트는 ‘아무것도 보내지 않음’과 ‘읽지 않는 헤더로 보냄’에 같은 메시지를 돌려준다. 그래서 릴레이를 쓰는 사용자는 셸에 키가 분명히 설정돼 있는데도 missing-header 오류만 바라보게 될 수 있다.

응답 헤더만으로 이 모호함이 완전히 해소되지는 않는다. 그래도 거부된 자격 증명과 인증 단계까지 도달하지 못한 자격 증명은 구분할 수 있다. 문구보다 헤더를 보려면 아래 여섯 요청을 실행해 보자.

show(){ shift; curl -sS -D - -o /dev/stdout "$@" \
  | grep -iE "^HTTP|www-authenticate|x-openai-authorization-error|request-id|x-should-retry|message"; }
A=(-X POST https://api.anthropic.com/v1/messages -H "anthropic-version: 2023-06-01"
   -H "content-type: application/json"
   -d '{"model":"claude-sonnet-4-5","max_tokens":8,"messages":[{"role":"user","content":"hi"}]}')
O=(-X POST https://api.openai.com/v1/responses -H "content-type: application/json"
   -d '{"model":"gpt-5.6","max_output_tokens":16,"input":"hi"}')

show a1 "${A[@]}" -H "x-api-key: sk-ant-api03-not-a-real-key"          # 거부됨
show a2 "${A[@]}"                                                      # 전달되지 않음
show a3 "${A[@]}" -H "Authorization: Bearer sk-ant-api03-not-a-real-key"  # 잘못된 헤더
show o1 "${O[@]}" -H "Authorization: Bearer sk-proj-not-a-real-key"    # 거부됨
show o2 "${O[@]}"                                                      # 전달되지 않음
show o3 "${O[@]}" -H "x-api-key: sk-proj-not-a-real-key"               # 잘못된 헤더

2026-07-31에 확인한 구분 기준이 되는 줄은 다음과 같다. 차이가 나는 필드만 남겼다.

o1 거부됨          HTTP/2 401   x-openai-authorization-error: 401   "code": "invalid_api_key"
o2 전달되지 않음  HTTP/2 401   www-authenticate: Bearer realm="OpenAI API"
o3 잘못된 헤더    HTTP/2 401   www-authenticate: Bearer realm="OpenAI API"
a1 거부됨          HTTP/2 401   "request_id": null   (request-id와 x-should-retry 없음)
a2 전달되지 않음  HTTP/2 401   request-id: req_011CdZnC9j…   x-should-retry: false
a3 잘못된 헤더    HTTP/2 401   request-id: req_011CdZnCDN…   x-should-retry: false

두 엔드포인트 모두 거부된 자격 증명에는 제공업체 고유의 인증 필드가 나타나고 challenge 헤더는 빠졌다. 반대로 인증 단계에 도달하지 못한 요청에서는 그 양상이 뒤집혔다. 반복 요청에서도 같은 구분이 나왔지만, 이는 두 엔드포인트에서 특정 날짜에 관찰한 결과일 뿐 문서화된 동작은 아니다. 자신의 제공업체에서도 그대로일 것이라 가정하지 말고 위 블록을 다시 실행해 보자. 거부됨 행에 해당한다면 OpenAI 또는 Claude 키 페이지에서 네 가지를 확인해야 한다. 값 앞뒤의 공백, 삭제 또는 폐기된 키, 호출 중인 프로젝트나 조직과 다른 곳에서 발급된 키, 클라이언트에 남아 있는 오래된 캐시 사본이다. 앞의 세 항목에 문제가 없을 때만 키를 재발급하자.

CLI가 실제로 보낸 자격 증명 확인하기

코딩 CLI가 내가 설정한 적 없는 invalid key를 보고한다면, 캐시된 자격 증명이 아니라 우선순위에서 밀린 자격 증명일 가능성이 높다. Claude Code는 여섯 가지 소스를 정해진 순서로 해석하며, 문서화된 이 우선순위는 각각 어떤 헤더로 전송되는지도 함께 정한다.

인증 우선순위와 각 자격 증명에 사용되는 헤더를 나열한 Claude Code 문서
우선순위소스전송 헤더
1클라우드 제공업체 자격 증명(CLAUDE_CODE_USE_BEDROCK, _VERTEX, _FOUNDRY)제공업체별 상이
2ANTHROPIC_AUTH_TOKENAuthorization: Bearer
3ANTHROPIC_API_KEYX-Api-Key
4apiKeyHelper 스크립트 출력반환된 값 기준
5CLAUDE_CODE_OAUTH_TOKENOAuth
6/login의 구독 로그인OAuth

승인된 ANTHROPIC_API_KEY는 구독 로그인보다 우선한다. 따라서 /login을 해도 이 키가 대체되지는 않으며, -p 플래그를 사용하면 키가 존재하는 한 항상 키가 사용된다. Anthropic이 안내하는 순서는 실행 셸에서 env | grep ANTHROPIC를 확인하고, 이어 /status를 실행한 뒤, 구독을 쓰려던 것이었다면 변수를 해제하는 것이다. 단, env 확인으로 볼 수 있는 것은 표의 2번과 3번뿐이다. 클라우드 제공업체, 헬퍼 스크립트, 로그인 중 무엇이 최종 소스로 선택됐는지는 /status가 알려 준다.

Invalid API key의 공식 진단 5단계를 보여 주는 Claude Code 오류 참고 문서

설정한 기억이 없는 자격 증명의 정체

한 보고 사례는 이 문제가 어떻게 나타나는지 잘 보여 준다.

"API env 변수가 전혀 없고 claude code를 pro max 계정에 정상적으로 연결했는데도 Claude가 API 과금 모드에 고정돼 있습니다"

관리자가 처음 확인한 것은 apiKeyHelper 설정 여부였다. 실제로 설정돼 있었고, 스크립트 전체 내용은 PLACEHOLDER_NOT_IMPLEMENTED_ON_MAC_YET를 출력하는 것이 전부였다. 쓰레기값을 반환하거나, 0이 아닌 상태 코드로 종료하거나, 아무것도 출력하지 않는 헬퍼는 플레이스홀더 자격 증명을 전송한다. API는 스크립트가 아니라 키에 관한 401으로 이를 거부한다. Claude Code는 이제 세 번 시도 안에 이 실패를 이름으로 보고한다. 같은 문서에는 v2.1.208 이전에는 헬퍼 실패가 약 열 번의 조용한 재시도 뒤 일반적인 401로 표시됐다고 기록돼 있다.

환경 변수는 모르는 사이에도 설정될 수 있다. Anthropic은 direnv, dotenv 셸 플러그인, IDE 터미널이 프로젝트 .env 파일의 오래된 키를 불러오는 경로라고 안내한다. 또한 헬퍼는 5분 후 또는 HTTP 401 발생 시 다시 실행되므로, 망가진 헬퍼는 일정 시간마다 다시 나타난다.

base URL이 게이트웨이를 가리킬 때

ANTHROPIC_BASE_URL이 LLM 게이트웨이를 가리킨다면 401 뒤에 나오는 문구는 Anthropic이 아닌 게이트웨이의 메시지다. 이 경우 /login으로는 바꿀 수 없다. 릴레이를 바라보는 OpenAI 호환 클라이언트도 마찬가지다. 오류 문자열 끝이 url: https://openrouter.ai/api/v1/responses로 끝나는 한 Codex 보고 사례는 다음과 같다.

"api key 관련 env 변수를 전부 지우고 auth 파일도 삭제해 봤지만 안 됐습니다. 여러 번 다시 로그인해도 오류가 계속됩니다"

로컬 자격 증명을 지운다고 해결되지 않는 이유는 base URL이 요청을 심사할 주체를 결정하기 때문이다. 해당 엔드포인트에 있는 서비스에 맞는 자격 증명을 사용해야 한다. Claude Code는 bearer token으로 인증하는 게이트웨이에 ANTHROPIC_AUTH_TOKEN을 사용하도록 문서화했다. 같은 값을 ANTHROPIC_API_KEY에 넣으면 대신 X-Api-Key로 전송되며, 이는 위 표의 3번 행이다. 다른 클라이언트는 자체 규약을 따르므로 실제로 어떤 헤더를 보내는지 확인해야 한다. Claude Code on the Web은 예외다. 항상 구독 자격 증명을 사용하며, 샌드박스에서 어느 변수를 설정해도 이를 덮어쓰지 못한다.

키는 정상인데 403이 나는 경우

이 섹션의 사례는 각각 특정 계정 상태나 지역 조건이 필요하므로 직접 재현한 내용은 아니다. 다만 제공업체 문서는 유효한 키로도 403이 발생할 수 있음을 분명히 밝히고 있다.

OpenAI의 오류 참고 문서에는 403 - Country, region, or territory not supported가 있다. 지역 검사에 관한 오류이며 키에는 문제가 없다. 그 두 행 위에는 반대 사례인 401 - IP not authorized가 있다. 요청 IP가 프로젝트 또는 조직의 허용 목록 밖에 있을 때 발생한다. 키는 유효하지만 호출자가 유효하지 않은 경우다.

403 Country region or territory not supported 위에 401 IP not authorized가 표시된 OpenAI 오류 코드 참고 문서

로그인 성공 뒤 API Error: 403 {"error":{"type":"forbidden","message":"Request not allowed"}}가 발생한다면 Anthropic은 세 가지 원인을 제시한다. 어느 것도 키 오타가 아니다. 비활성 상태인 Pro 또는 Max 구독, "Claude Code" 또는 "Developer" 역할이 없는 Console 계정, 요청을 방해하는 기업 프록시가 원인일 수 있다. 플랫폼 API에서 403 - permission_error는 해당 리소스에 대한 키 권한이 없다는 뜻이며, 조직 및 워크스페이스 설정을 기준으로 확인된다. 또한 compliance 엔드포인트에서는 유효한 키라도 scope가 맞지 않으면 설계상 401이 아니라 403을 반환한다.

FAQ

Claude API의 오류 코드 403은 무엇을 뜻하나요?

두 가지 의미가 있다. permission_error는 해당 리소스에 대한 키 권한이 없다는 뜻으로, 조직 또는 워크스페이스 설정 문제다. 로그인 후 나타나는 Request not allowed는 구독 상태, 누락된 Console 역할 또는 프록시 문제를 가리킨다.

401은 재시도해 볼 가치가 있나요?

401만으로는 그렇지 않다. 거부되었거나 아예 없는 자격 증명은 다음 시도에서도 같은 결과를 낸다. 반면 429는 백오프하기 전에 Retry-After를 준수하는 것이 해결책이다. 스스로 해결될 수 있는 401은 apiKeyHelper 사례뿐이며, Claude Code는 오류를 보고하기 전에 이미 두 번 더 재시도한다.

함께 읽기

  • OpenRouter 429 해결: Provider Error인가, Rate Limit인가?
  • OpenAI API에서 upstream connect error or disconnect/reset before headers가 의미하는 것

>_AIReiter 모델 디렉터리

이 가이드와 관련된 모델로 빠르게 API 접근

Claude Sonnet 5

Chat

고급 추론, 코딩, 일상 업무를 위한 균형 잡힌 Claude 모델입니다.

AnthropicAPI Key 생성 >

GPT-5.6 Sol

Chat

까다로운 코딩, 추론, 장문형 에이전트 작업을 위한 프리미엄 GPT-5.6 텍스트 모델.

OpenAIAPI Key 생성 >

Claude Fable 5

Chat

심층 추론과 복잡한 장문 작업을 위한 프리미엄 Claude 모델입니다.

AnthropicAPI Key 생성 >

Claude Opus 4.8

Chat

까다로운 추론과 전문적인 작업을 위한 고성능 Claude 모델입니다.

AnthropicAPI Key 생성 >

Claude Opus 5

Chat

복잡한 추론, 코딩, 긴 컨텍스트의 전문 작업을 위한 프리미엄 Claude 모델입니다.

anthropicAPI Key 생성 >

최근 게시글

GPT-5.6 가격 인하: Luna와 Terra, 이제 실제 비용은 얼마일까

2026-07-31

OpenRouter 429 해결법: Provider Error인가, Rate Limit인가?

2026-07-31

DeepSeek V4 Flash vs GLM-5.2: 0731 업데이트 직접 테스트

2026-07-31

B2B 광고 인텔리전스는 결국 HTML에서 온다: 리디자인에도 버티는 파서 설계법

2026-07-31
AIREITER

문의가 있으신가요? 연락처
[email protected]

LLM

Gemini 3.6 FlashGemini 3.1 ProKimi K3Gemini 3 ProGemini 2.5 Pro

AI 비디오

Kling 3.0 Motion ControlSora 2 ProKling 3.0 TurboSora 2Kling 3.0

AI 이미지

FLUX.2 ProGPT-Image 2Wan 2.7 Image ProGPT 4o ImageSeedream 5.0 Pro

블로그

모두 보기 →

회사

개인정보 처리방침서비스 약관환불 정책

© 2026 AIReiter. All rights reserved.