본문으로 건너뛰기
Gujo Developers 로그인

인증과 API 키

로그인(OAuth)과 계정 API 키 가운데 무엇을 쓸지, 키의 모양, 능력, 상품 범위 키, 한도와 폐기, 오류 코드.

Markdown 으로 보기

요청 머리글

모든 호출은 Authorization: Bearer <키> 로 인증합니다. 공개 API 의 정본 호스트는 api.gujo.ai 입니다.

curl https://api.gujo.ai/api/products \
  -H "Authorization: Bearer $GUJO_API_KEY"

예전 클라이언트가 부르는 gujo.ai/api/... 도 api.gujo.ai 로 넘어가지만, 그 길은 authorization·content-type·accept·accept-language·user-agent 와 X-* 머리글만 넘깁니다. 새 코드는 언제나 api.gujo.ai 를 부릅니다.

로그인(OAuth)과 API 키

에이전트를 고객 MCP 에 붙일 때는 로그인이 먼저입니다. 키는 사람이 브라우저로 로그인할 수 없는 곳에서 씁니다.

로그인(OAuth) 계정 API 키
어디에 고객 MCP(https://api.gujo.ai/api/mcp)만 계정 API 전체와 고객 MCP
언제 Claude Code·Codex·Cursor·VS Code·Claude.ai 처럼 사람이 쓰는 MCP 클라이언트 CI, 서버의 스크립트, 헤드리스 에이전트, curl 같은 직접 호출
받는 법 클라이언트에 서버 주소만 넣고, 브라우저에서 로그인해 권한에 동의합니다 개발자 설정에서 만들고, 한 번 보이는 값을 환경 변수에 넣습니다
권한 동의한 권한(기본 mcp.read·products.read) 만들 때 고른 능력
수명 접근 토큰 1시간, 클라이언트가 스스로 갱신(30일 쓰지 않으면 만료) 정한 만료일까지(없으면 폐기할 때까지)
끊기 계정 보안 설정의 연결된 앱 개발자 설정의 키 목록에서 폐기

권한 이름과 판정은 둘이 같습니다. 아래 능력 표가 로그인 권한에도 그대로 적용됩니다. 로그인으로 받은 토큰은 고객 MCP 에서만 받으므로, 그 토큰으로 다른 계정 API 를 부르면 401 invalid_api_key 입니다. 연결 순서와 토큰 수명은 MCP 연결하기에 있습니다.

직접 MCP 클라이언트를 만든다면 표준 OAuth 흐름(MCP 2025-11-25 authorization)을 따릅니다. 시작점은 보호 리소스 메타데이터 https://api.gujo.ai/.well-known/oauth-protected-resource/api/mcp 와 인가 서버 메타데이터 https://account.gujo.ai/.well-known/oauth-authorization-server 입니다. 인가 코드 + PKCE(S256)만 받고, 앱 등록은 클라이언트 메타데이터 문서(CIMD)나 동적 등록(POST /oauth/register)으로 합니다. 인가·토큰 요청에는 resource=https://api.gujo.ai/api/mcp 를 싣습니다.

키의 모양

  • 키는 gujo_ 로 시작합니다.
  • 서버는 키의 SHA-256 해시만 저장합니다. 원문은 만들 때 한 번만 보이고, 그 뒤에는 Gujo 도 다시 보여 줄 수 없습니다.
  • 개발자 설정 화면의 키 목록에는 이름, 키 앞 14글자(접두사), 능력이 보입니다. 어느 키인지 알아볼 때 접두사를 씁니다.

능력

키마다 쓸 수 있는 능력을 따로 적습니다. 문마다 필요한 능력은 API 참조의 ability 칸에 있고, 비어 있으면 유효한 키만 있으면 됩니다.

능력 여는 문 처음부터 가진 키
products.read 라이브러리, 상품 목록·상세, 업데이트 확인, 설치 계획, 설정 진행 조회, 상품 라이선스 직접 만든 키, 기기 로그인 키
orders.read 내 주문, 청구서, 결제 수단 없음(만들 때 골라서 더함)
subscriptions.read 내 구독 없음(만들 때 골라서 더함)
mcp.read 고객 MCP(POST /api/mcp) 직접 만든 키
setup-progress.write 상품 설정 진행 기록 없음(만들 때 골라서 더함)
device.install 설치 기록, 앱 배포 피드와 다운로드 직접 만든 키, 기기 로그인 키
device.entitlements 보유 상품, 라이선스 확인, Pass 확인 기기 로그인 키
device.activate 앱 일괄 활성화 기기 로그인 키
device.usage 제품 사용량 업로드 기기 로그인 키
support.report 앱 문제 신고 기기 로그인 키
  • 직접 만든 키의 기본 능력은 products.read·mcp.read·device.install 입니다.
  • gujoctl 이나 Gujo Cloud Apps 의 기기 로그인으로 받은 키는 products.read·device.entitlements·device.activate·device.install·device.usage·support.report 여섯 가지를 받습니다. orders.read·subscriptions.read·mcp.read 가 필요하면 개발자 설정 화면에서 키를 따로 만듭니다.
  • support.staff·commerce.staff·design.staff 는 Gujo 운영자용 능력입니다. 일반 계정의 키에 적어도 통하지 않습니다.

상품 범위 키

키는 대개 계정 전체에 걸립니다. Gujo Cloud Apps 가 앱을 활성화할 때 받는 키처럼 상품 하나에 묶인 키도 있습니다.

  • 상품 하나에 묶인 키로 GET /api/library 를 부르면 그 상품 하나만 나옵니다.
  • 다른 상품의 경로를 부르면 403 product_api_key_scope_required 입니다.

한도와 만료

  • 살아 있는 키는 범위마다 3개까지입니다. 계정 전체 키와 상품마다 묶인 키는 따로 셉니다.
  • 직접 만들 때 자리가 없으면 발급이 거절되고 화면에 한도 안내가 나옵니다. 키 하나를 폐기하면 자리가 생깁니다.
  • 기기 로그인은 자리가 없으면 같은 클라이언트의 키 가운데 가장 오래 쓰지 않은 키를 폐기하고 새 키를 받습니다.
  • 직접 만든 키는 만들 때 정한 만료일(없으면 폐기할 때까지)까지 쓸 수 있습니다. 기기 로그인 키는 90일 동안 쓰지 않으면 만료되고, 쓸 때마다 그 기한이 늘어납니다.

폐기

  • 개발자 설정 화면의 키 목록에서 언제든 폐기합니다.
  • gujoctl 키는 gujoctl logout 이 서버에서 폐기한 뒤 기기에서 지웁니다.
  • 폐기했거나 만료된 키는 다음 요청부터 401 invalid_api_key 를 받습니다.

키가 새었다고 생각되면 먼저 폐기하고 새 키를 만듭니다.

오류

인증·권한 오류의 본문은 {"message": "...", "error": "<코드>"} 입니다. /api/* 는 로그인 화면으로 보내지 않고 언제나 JSON 으로 답합니다.

상태 error 뜻
401 missing_api_key Authorization 머리글이 없습니다
401 invalid_api_key 모르는 키이거나, 폐기·만료된 키입니다
403 missing_api_key_ability 키에 그 문의 능력이 없습니다
403 product_entitlement_required 그 상품의 이용권이 없습니다
403 product_api_key_scope_required 상품 하나에 묶인 키로 다른 상품을 불렀습니다
404 — 대상이 없습니다
422 — 입력 검증 실패. 본문은 {message, errors} 입니다
429 — 속도 제한을 넘었습니다. API 전체에 분당 60회가 걸리고, 일부 문은 따로 더 좁은 제한이 있습니다

능력 검사는 대상을 찾기 전에 돌아갑니다. 그래서 능력이 없는 키는 그 id 가 있는지 알 수 없습니다(404 대신 403).

키를 다루는 법

  • 키는 머리글로만 보냅니다. 주소의 쿼리나 경로에 넣지 않습니다.
  • 설정 파일과 저장소에는 키 값이 아니라 환경 변수 이름만 둡니다. MCP 연결하기의 키로 붙이는 설정도 모두 GUJO_API_KEY 를 가리킵니다.
  • 설치 계획이 주는 서명 다운로드 주소에는 키를 보내지 않습니다. 키는 API 호스트에만 갑니다.
  • 사람이 쓰는 MCP 클라이언트라면 키 대신 로그인으로 연결합니다. 키를 설정에 둘 일이 없어집니다.