프로그래밍 방식 회원가입: Agent 및 CI를 위한 지갑 로그인과 API Key 생성

AI 에이전트, 스크립트 및 CI 워크플로를 위해 브라우저 없이 이더리움 지갑 서명(EIP-191)을 사용하여 프로그래밍 방식으로 가입하고 API key를 생성하세요.

브라우저 없이 실행되는 자율 AI 에이전트, CI 파이프라인 및 자동화 스크립트를 위해 BlockVectra는 이더리움 지갑 서명(EIP-4361 / EIP-191) 기반의 프로그래밍 방식 로그인 및 계정 개설 워크플로를 제공합니다.

Key security

개인키, 세션 토큰 또는 API key를 AI와의 대화에 붙여넣거나 MCP 툴 인수로 전달하지 마세요.

가입하기 전에 먼저 키가 필요 없는 공개 엔드포인트 https://api.blockvectra.com/v1/robinhood_mainnet/public을 사용해 볼 수 있습니다(지갑용 JSON-RPC 메서드 전용, Data API는 키 필요, 메서드 및 한도는 /v1/chains 기준). 할당량이 부족한 경우 계정에 가입하세요.

워크플로 개요

프로그래밍 방식 등록 및 키 발급 흐름은 다음 4단계로 구성됩니다:

  1. 챌린지 요청: POST /auth/siwe/challenge로 요청을 전송하여 서버가 생성한 로그인 메시지를 받습니다.
  2. 메시지 서명: EIP-191(personal_sign)을 사용하여 이더리움 EOA 지갑으로 해당 메시지에 정확히 서명합니다.
  3. 로그인 / 계정 개설: 원본 메시지와 서명을 POST /auth/siwe/login에 제출합니다. 지갑의 첫 로그인 시 계정이 자동으로 생성됩니다(account_created: true). 신규 계정 가입 시 30,000,000 CU 무료 제공 — 신용카드 불필요.
  4. API key 생성: 세션 토큰을 사용하여 POST /keys를 호출하고 API key를 생성합니다.

실행 가능한 전체 예제

여기서 시작하세요: 로컬 이더리움 EOA 서명기를 사용해 키를 생성하고 eth_blockNumber로 검증합니다. Bash 예제의 경우 curl, jq 및 Foundry cast가 필요합니다. 지갑 자격 증명은 로컬 서명 환경에 보관하세요.

전체 스타터 템플릿: blockvectra/agent-quickstart

다음 스크립트는 지갑 자격 증명을 읽고, 챌린지 및 로그인 과정을 완료하며, API key를 발급하고, 환경 변수 설정을 위해 export BLOCKVECTRA_API_KEY=...를 내보내거나 출력한 뒤 검증용 eth_blockNumber 요청을 보냅니다:

새 키가 활성화되는 데 몇 초 정도 걸릴 수 있으며, 아래 예제는 자동으로 재시도합니다.

BASE=https://console-api.blockvectra.com/v1
# $ADDR: Ethereum wallet address (0x...)
# $PK: wallet private key, loaded from a secrets manager (never hardcode in scripts)

# 1. Fetch server-generated SIWE message (omit Origin header)
curl -s "$BASE/auth/siwe/challenge" -H 'Content-Type: application/json' \
  -d "{\"address\":\"$ADDR\",\"purpose\":\"login\"}" > challenge.json
jq -r .message challenge.json > msg.txt

# 2. Sign the exact message with EIP-191 personal_sign
SIG=$(cast wallet sign --private-key "$PK" "$(cat msg.txt)")

# 3. Submit verbatim message and signature (omit Origin header) to log in (ref is optional)
jq -n --rawfile m msg.txt --arg s "$SIG" '{message: ($m | rtrimstr("\n")), signature: $s, ref: "docs-signup"}' |
  curl -s "$BASE/auth/siwe/login" -H 'Content-Type: application/json' -d @- > session.json
TOKEN=$(jq -r .session.token session.json)

# 4. Create an API key (the secret is returned only once)
KEY_RESP=$(curl -s "$BASE/keys" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"label":"agent-key"}')
export BLOCKVECTRA_API_KEY=$(echo "$KEY_RESP" | jq -r .api_key)

# 5. Call JSON-RPC with the key in the x-api-key request header
RPC_DEADLINE=$((SECONDS + 10))
while true; do
  RPC_TIMEOUT=$((RPC_DEADLINE - SECONDS))
  if ((RPC_TIMEOUT <= 0)); then
    printf '%s' "${RPC_BODY:-}"
    break
  fi
  RPC_RESP=$(curl -s --max-time "$RPC_TIMEOUT" -w '\n%{http_code}' "https://api.blockvectra.com/v1/robinhood_mainnet" \
    -H "x-api-key: $BLOCKVECTRA_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}') || { rc=$?; echo "request failed (curl exit $rc)" >&2; exit $rc; }
  RPC_STATUS=${RPC_RESP##*$'\n'}
  RPC_BODY=${RPC_RESP%$'\n'*}
  if ((SECONDS + 2 < RPC_DEADLINE)) &&
    printf '%s' "$RPC_BODY" | jq -e --arg status "$RPC_STATUS" '
      ($status == "401" and .error.data.reason == "invalid_api_key") or
      ($status == "503" and .error.code == -32021)
    ' >/dev/null 2>&1; then
    sleep 2
  else
    printf '%s' "$RPC_BODY"
    break
  fi
done

기본 URL 및 프로그래밍 모드

모든 인증 및 키 관리 엔드포인트는 공식 기본 URL을 사용합니다:

https://console-api.blockvectra.com/v1

Origin 헤더 생략

프로그래밍 방식 요청은 프로그래밍 모드로 작동합니다:

  • 챌린지(POST /auth/siwe/challenge) 및 로그인(POST /auth/siwe/login) 요청 모두 Origin 헤더를 포함해서는 안 됩니다(curl 및 표준 HTTP 클라이언트는 이 헤더를 기본적으로 생략하므로 수동으로 추가하지 마세요).
  • Origin 헤더를 전송했지만 구성된 웹 콘솔 도메인이 아닌 경우(빈 문자열 또는 null 포함), 챌린지 요청은 HTTP 400 invalid_request를 반환합니다.
  • 로그인 시 모드가 챌린지 모드와 일치하지 않는 경우(예: Origin 없이 프로그래밍 방식 챌린지를 요청한 후 Origin 헤더를 포함하여 로그인을 제출하거나 그 반대의 경우), 로그인 요청은 reason: domain_mismatch와 함께 HTTP 400 siwe_invalid를 반환합니다.

메시지 무결성 및 지갑 요구사항

  • 메시지 원본 서명 및 제출: 클라이언트는 챌린지 엔드포인트가 반환한 메시지 텍스트를 있는 그대로 정확히 서명하고 제출해야 합니다. 공백, 도메인, 체인 ID 또는 기타 필드를 변경하지 마세요. 어떠한 수정이라도 가해지면 reason: signature와 함께 HTTP 400 siwe_invalid가 발생합니다.
  • 지원되는 지갑: Ethereum 메인넷(Chain ID 1) EOA(Externally Owned Accounts). 서명은 65바이트 ECDSA 서명(personal_sign)이어야 합니다. 컨트랙트 지갑(EIP-1271) 및 스마트 계정은 지원되지 않습니다.
  • 챌린지 유효 기간: 각 챌린지 nonce는 일회용이며 5분 후 만료됩니다.

요청 본문 및 가입 귀속 (선택 사항)

POST /auth/siwe/login 요청 본문은 필수 인증 파라미터와 선택 사항인 가입 귀속(attribution) 필드를 받습니다:

  • 필수 필드:
    • message: 챌린지 엔드포인트에서 획득한 완전한 SIWE 메시지 문자열.
    • signature: 이더리움 지갑으로 EIP-191을 통해 message에 서명하여 생성된 65바이트 16진수 서명(0x 접두사 포함).
  • 선택 귀속 필드 (새 계정이 생성될 때 한 번만 저장되며, 이후 로그인에서는 무시됨):
    • ref: ^[a-z0-9._-]{1,64}$ 정규식과 일치하는 소문자 채널 토큰(소문자 ASCII 영문, 숫자, ., _, -, 1~64자). 예를 들어 자율 에이전트는 프레임워크나 런타임 식별자(예: my-agent.v1)로 설정할 수 있습니다. 규격을 준수하지 않는 값(대문자, 빈 문자열, 길이 초과 또는 지원되지 않는 문자 포함)은 대소문자 변환 없이 HTTP 400 invalid_request를 반환하며 계정 생성을 차단합니다. 해당 사항이 없으면 생략하거나 null을 전달하세요.
    • referrer: 유입 출처 URL 또는 호스트 이름 문자열. 문자열이 아닌 타입만 HTTP 400을 반환합니다.

signup_method와 같이 정의되지 않은 필드를 전송하면 HTTP 400 invalid_request가 반환됩니다.

세션 토큰 및 API Key

세션 토큰 수명 주기

  • 형식: rgs_ 뒤에 64자의 소문자 16진수 문자가 붙습니다.
  • 유효 기간: 절대 수명 7일, 24시간 동안 유휴 상태일 경우 자동 만료.
  • 리프레시 토큰 없음: 세션 토큰이 만료되면 새로운 챌린지 및 로그인 흐름을 시작해야 합니다.
  • 헤더: Authorization: Bearer rgs_... 요청 헤더에 세션 토큰을 전달합니다.

API Key 생성

  • 세션 토큰과 함께 POST /keys를 호출하여 API key를 생성합니다(rgw_ 뒤에 64자의 16진수 문자가 붙음).
  • 계정당 해지되지 않고 만료되지 않은 키(active + disabled)는 최대 20개까지 가능하며, 만료된 키는 계산에 포함되지 않습니다. 이를 초과하면 reason: active_keys 및 limit: 20과 함께 HTTP 409 key_limit_reached가 반환되므로 기존 키를 먼저 해지해야 합니다. 이 상한은 계정의 모든 ID, 세션 및 체인 전체에 적용됩니다. 키 생성 및 순환도 24시간당 20개로 제한되며, 초과 시 Retry-After: 3600과 함께 HTTP 429 rate_limited가 반환됩니다.
  • 선택적 상한 및 만료: cu_cap(키의 누적 수명 CU 상한, 소프트 캡)과 만료 시간(expires_in_secs 또는 expires_at, 키 정책에서 허용하는 최대 일수까지)을 지정할 수 있습니다. 만료되거나 상한이 소진되면 서버는 403(JSON-RPC -32025, reason key_expired 또는 key_cap_exhausted)을 반환합니다.
  • 보안 secret인 api_key는 생성 시 단 한 번만 반환됩니다. 즉시 시크릿 관리자나 환경 변수에 안전하게 저장하세요.
  • 하나의 API key로 JSON-RPC 및 Data API가 지원하는 모든 체인에서 사용할 수 있습니다.

세션이나 API Key를 분실했나요?

BlockVectra에서 에이전트의 계정 식별자는 가입 시 사용한 이더리움 지갑 주소에 바인딩됩니다. 세션 토큰이 만료되었거나 API key를 분실 또는 유출한 경우, 해당 지갑만을 사용하여 완전한 제어권을 복구할 수 있습니다:

  1. 동일한 지갑으로 재인증: 챌린지를 요청하고, 동일한 지갑으로 서명한 뒤, 로그인 요청(POST /auth/siwe/login)을 제출합니다. 서버가 서명을 검증하고, account_created: false로 기존 계정에 로그인하며 새 세션 토큰을 발급합니다.
  2. 새 API Key 생성: 새 세션 토큰을 사용하여 {"label": "..."} 및 Authorization: Bearer <token> 헤더와 함께 POST /keys를 호출합니다. 엔드포인트는 key에 생성된 키 세부 정보와 api_key에 일회용 시크릿을 담아 HTTP 201을 반환합니다. 즉시 이 키를 환경 변수나 시크릿 관리자에 저장하세요.
  3. 계정의 모든 키 목록 조회:
    • 엔드포인트: GET /keys
    • 헤더: Authorization: Bearer <token>
    • 쿼리 파라미터: 선택적 include_revoked=true(true인 경우 해지된 키 포함, 기본값은 활성/비활성화 키만 반환).
    • 응답: {"items": [...]} JSON과 함께 HTTP 200. items 배열의 각 요소에는 다음이 포함됩니다:
      • key_id: 고유 키 식별자 (string)
      • label: 키 라벨 (string 또는 null)
      • status: 상태 ("active", "disabled", 또는 "revoked")
      • created_at: 생성 타임스탬프 (ISO 8601 문자열)
      • revoked_at: 해지 타임스탬프 (문자열, 해지되지 않은 경우 null)
  4. 미사용 또는 유출된 키 해지:
    • 엔드포인트: POST /keys/{key_id}/revoke (참고: 경로에 대상 key_id를 포함하는 POST 사용, 빈 요청 본문)
    • 헤더: Authorization: Bearer <token>
    • 동작: 멱등성 보장. active 또는 disabled 상태의 키 모두 해지 가능합니다. 이미 해지된 경우 변경 없이 HTTP 200을 반환합니다. 해지된 후 해당 키를 사용하는 요청은 거부됩니다.
    • 응답: 해지된 키 객체를 반환하는 HTTP 200(필드는 위의 키 객체와 일치하며 status: "revoked" 및 revoked_at 타임스탬프 포함).

Key and secret security

지갑 개인키와 API key는 환경 변수나 시크릿 관리자에 보관하세요. 코드 저장소에 커밋하거나, 로그에 기록하거나, AI 채팅 대화에 붙여넣지 마세요.

보안 권장사항

  • 단기 키 사용 및 작업 완료 후 해지: 자동화되거나 일시적인 작업의 경우 expires_in_secs로 수명이 짧은 키를 생성하고, 작업이 완료되면 POST /keys/{key_id}/revoke를 통해 즉시 해지하세요.

가입 속도 제한 (signup_rate_limited)

계정 생성에는 가입 속도 제한이 적용됩니다. IP별 토큰 버킷 용량은 100개 계정이며, IPv4 주소 또는 IPv6 /64 프리픽스당 시간당 100개 계정 비율로 채워집니다. 이는 SIWE와 OAuth 가입이 공유합니다:

  • 가입 제한을 초과하면 POST /auth/siwe/login은 대기할 시간(초)을 나타내는 Retry-After 헤더와 함께 HTTP 429 signup_rate_limited를 반환합니다.
  • reason 필드는 제한 범위를 구분합니다:
    • per_ip: 요청한 IP 프리픽스의 등록 예산이 소진되었습니다.
    • global: 플랫폼 전체 통합 가입 한도가 소진되었습니다.
  • 가입 속도 제한은 신규 계정 등록 시에만 평가됩니다. 기존 계정의 로그인은 가입 속도 제한으로 차단되지 않습니다.

관련 리소스

다음 단계

최종 수정일:

이 페이지의 내용