토큰은 유효했습니다. 그런데도 제 헤드리스 에이전트는 401 에러를 냈습니다.
코드를 통해 Claude를 호출하는 두 개의 작은 도구를 만들었습니다. 하나는 커밋 메시지를 생성하고, 다른 하나는 프로필을 업데이트합니다.
코드는 완벽해 보였습니다. 환경 변수에서 API 키를 가져오고, Anthropic API로 직접 HTTPS 요청을 보낸 뒤, JSON 응답을 파싱했습니다.
하지만 매번 401 에러와 함께 실패했습니다.
문제는 코드가 아니었습니다. 문제는 인증 방식이었습니다.
저는 생(raw) API 키를 사용하지 않습니다. 구독을 통해 Claude Code를 사용합니다. 이는 Claude CLI를 통한 OAuth를 사용합니다. 이는 제 스크립트가 예상했던 방식과는 다른 시스템이었습니다.
제 환경의 API 키 변수에는 오래되었거나 비어 있는 값이 들어 있었습니다. 스크립트는 값이 있는 것을 보고 유효하다고 판단했습니다. 결국 잘못된 유형의 인증 정보로 요청이 전송되었습니다.
해결 방법은 간단했습니다. 직접적인 API 호출을 중단했습니다. 대신, 이미 유효한 세션을 가지고 있는 CLI를 사용하도록 스크립트를 수정했습니다.
기존 방식:
urllib를 사용하여 API 키로 요청을 보냅니다.
새로운 방식:
subprocess를 사용하여 "claude" 명령어를 직접 실행합니다.
CLI가 세션, 토큰, 만료 처리를 알아서 해줍니다.
이러한 실수는 헤드리스(headless) 환경에서 위험합니다. 사람은 터미널에서 에러를 직접 보지만, cron 작업이나 CI 파이프라인은 조용히 실패합니다. 며칠 동안 눈치채지 못할 수도 있습니다.
다른 곳에서도 이와 동일한 패턴을 볼 수 있습니다:
- 도구는 개인 액세스 토큰(personal access token)을 찾지만 시스템은 OIDC를 사용하는 경우.
- 스크립트는 AWS 키를 읽으려 하지만 시스템은 IAM 역할을 사용하는 경우.
토큰은 존재합니다. 토큰의 형식도 올바릅니다. 기본적인 검사는 통과하지만 잘못된 메커니즘을 사용하고 있는 것입니다.
이를 방지하려면 다음 규칙을 따르세요:
- 코드를 작성하기 전에 환경이 대화형으로 어떻게 인증하는지 확인하세요. 단순히 API 문서만 따르지 마세요.
os.environ을 신뢰하지 마세요. 값이 존재하더라도 오래되었거나 잘못되었을 수 있습니다.- CLI 도구가 인증을 처리해 준다면 그것을 사용하세요. 인증 로직을 직접 다시 만드는 대신 CLI를 호출(shell out)하세요.
- 401 에러가 발생하면 요청 코드를 수정하기 전에 인증 정보 경로(credential path)를 먼저 확인하세요.
Source: https://dev.to/enjoy_kumawat/the-token-was-valid-my-headless-agent-401d-anyway-3bgl
Optional learning community: https://t.me/GyaanSetuAi
