การลงทะเบียนแบบเป็นโปรแกรม: การเข้าสู่ระบบด้วยกระเป๋าเงินและการสร้าง API Key สำหรับ Agent และ CI

ลงทะเบียนและสร้าง API key แบบเป็นโปรแกรมด้วยลายเซ็นกระเป๋าเงิน Ethereum (EIP-191) โดยไม่ต้องใช้เบราว์เซอร์ สำหรับ AI agent, สคริปต์ และเวิร์กโฟลว์ CI

สำหรับ autonomous AI agent, ไปป์ไลน์ CI และสคริปต์อัตโนมัติที่ทำงานโดยไม่มีเบราว์เซอร์ BlockVectra มีเวิร์กโฟลว์การเข้าสู่ระบบและเปิดบัญชีแบบเป็นโปรแกรมโดยอิงจากลายเซ็นกระเป๋าเงิน Ethereum (EIP-4361 / EIP-191)

ความปลอดภัยของคีย์

ห้ามวาง private key, session token หรือ API key ลงในบทสนทนากับ AI หรือส่งเป็นอาร์กิวเมนต์ของเครื่องมือ MCP โดยเด็ดขาด

ก่อนที่จะลงทะเบียน คุณสามารถทดลองใช้ public endpoint แบบไม่ต้องใช้คีย์ https://api.blockvectra.com/v1/robinhood_mainnet/public ดูก่อนได้ (เฉพาะเมธอดกระเป๋าเงิน JSON-RPC เท่านั้น ส่วน Data API จำเป็นต้องใช้คีย์ ทั้งนี้ เมธอดและขีดจำกัดเป็นไปตาม /v1/chains) และสามารถลงทะเบียนบัญชีได้หากโควตาไม่เพียงพอ

ภาพรวมขั้นตอนการทำงาน

ขั้นตอนการลงทะเบียนและจัดสรรคีย์แบบเป็นโปรแกรมประกอบด้วย 4 ขั้นตอน:

  1. ขอ Challenge: ส่งคำขอไปยัง POST /auth/siwe/challenge เพื่อรับข้อความเข้าสู่ระบบที่สร้างขึ้นโดยเซิร์ฟเวอร์
  2. ลงนามข้อความ: ลงนามข้อความที่ได้รับอย่างแม่นยำด้วยกระเป๋าเงิน Ethereum EOA โดยใช้ EIP-191 (personal_sign)
  3. เข้าสู่ระบบ / เปิดบัญชี: ส่งข้อความตามตัวอักษรและลายเซ็นไปยัง POST /auth/siwe/login ในการเข้าสู่ระบบครั้งแรกของกระเป๋าเงิน บัญชีจะถูกสร้างขึ้นโดยอัตโนมัติ (account_created: true) บัญชีใหม่รับ 30,000,000 CU เมื่อลงทะเบียน — ไม่ต้องใช้บัตรเครดิต
  4. สร้าง API key: ใช้ session token เพื่อเรียก POST /keys และสร้าง API key

ตัวอย่างที่สามารถรันได้ฉบับสมบูรณ์

เริ่มต้นที่นี่: ใช้ตัวลงนาม Ethereum EOA ภายในเครื่อง, สร้างคีย์ และตรวจสอบความถูกต้องด้วย eth_blockNumber สำหรับตัวอย่าง Bash คุณจำเป็นต้องมี curl, jq และ Foundry cast เก็บรักษาข้อมูลประจำตัวของกระเป๋าเงินไว้ในสภาพแวดล้อมการลงนามภายในเครื่องของคุณ

เทมเพลตเริ่มต้นฉบับสมบูรณ์: blockvectra/agent-quickstart

สคริปต์ต่อไปนี้จะอ่านข้อมูลประจำตัวของกระเป๋าเงิน, ดำเนินการตามลำดับขั้นตอน challenge และการเข้าสู่ระบบ, จัดสรร API key, export หรือพิมพ์ export BLOCKVECTRA_API_KEY=... สำหรับการกำหนดค่าสภาพแวดล้อม และส่งคำขอ eth_blockNumber เพื่อตรวจสอบความถูกต้อง:

คีย์ใหม่จะใช้เวลา 2-3 วินาทีกว่าจะเริ่มใช้งานได้ ตัวอย่างเหล่านี้จะลองใหม่อัตโนมัติ

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

Base URL และโหมดการทำงานแบบเป็นโปรแกรม

endpoint การยืนยันตัวตนและการจัดการคีย์ทั้งหมดใช้ base URL อย่างเป็นทางการดังนี้:

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

การละเว้นส่วนหัว Origin

คำขอแบบเป็นโปรแกรมจะทำงานใน โหมดโปรแกรม (programmatic mode):

  • ทั้งคำขอ challenge (POST /auth/siwe/challenge) และการเข้าสู่ระบบ (POST /auth/siwe/login) ต้องไม่รวมส่วนหัว Origin (curl และไคลเอนต์ HTTP มาตรฐานจะละเว้นส่วนหัวนี้เป็นค่าเริ่มต้นอยู่แล้ว อย่าเพิ่มส่วนหัวนี้ด้วยตนเอง)
  • หากมีการส่งส่วนหัว Origin แต่ไม่ใช่โดเมนของเว็บคอนโซลที่กำหนดค่าไว้ (รวมถึงสตริงว่างหรือ null) คำขอ challenge จะส่งคืน HTTP 400 invalid_request
  • หากโหมดขณะเข้าสู่ระบบไม่ตรงกับโหมดของ challenge (เช่น ขอ challenge แบบโปรแกรมโดยไม่มี Origin แต่ส่งการเข้าสู่ระบบพร้อมส่วนหัว Origin หรือในทางกลับกัน) คำขอเข้าสู่ระบบจะส่งคืน HTTP 400 siwe_invalid พร้อม reason: domain_mismatch

ความสมบูรณ์ของข้อความและข้อกำหนดของกระเป๋าเงิน

  • การลงนามและการส่งข้อความตามตัวอักษร: ไคลเอนต์ต้องลงนามและส่งข้อความตรงตามที่ได้รับจาก endpoint ของ challenge ทุกประการ อย่าแก้ไขช่องว่าง, โดเมน, chain ID หรือฟิลด์ใดๆ การแก้ไขใดๆ จะส่งผลให้ได้รับ HTTP 400 siwe_invalid พร้อม reason: signature
  • กระเป๋าเงินที่รองรับ: Externally Owned Accounts (EOA) บน Ethereum mainnet (Chain ID 1) ลายเซ็นต้องเป็นลายเซ็น ECDSA ขนาด 65 ไบต์ (personal_sign) ไม่รองรับกระเป๋าเงินแบบสัญญาอัจฉริยะ (EIP-1271) และ smart account
  • อายุการใช้งานของ Challenge: แต่ละ challenge nonce จะใช้งานได้เพียงครั้งเดียวและหมดอายุหลังจาก 5 นาที

เนื้อหาคำขอและการระบุที่มาของการลงทะเบียน (ไม่บังคับ)

เนื้อหาคำขอ POST /auth/siwe/login รับพารามิเตอร์การยืนยันตัวตนที่จำเป็นและฟิลด์ระบุที่มาของการลงทะเบียนที่ไม่บังคับ:

  • ฟิลด์ที่จำเป็น:
    • message: สตริงข้อความ SIWE ฉบับสมบูรณ์ที่ได้รับจาก challenge endpoint
    • signature: ลายเซ็นเลขฐานสิบหกขนาด 65 ไบต์ (ขึ้นต้นด้วย 0x) ที่สร้างขึ้นจากการลงนาม message ผ่าน EIP-191 ด้วยกระเป๋าเงิน Ethereum
  • ฟิลด์ระบุที่มาที่ไม่บังคับ (บันทึกเพียงครั้งเดียวเมื่อสร้างบัญชีใหม่ และจะถูกละเว้นในการเข้าสู่ระบบครั้งถัดไป):
    • ref: โทเค็นช่องทางที่เป็นตัวพิมพ์เล็กตรงตาม ^[a-z0-9._-]{1,64}$ (ตัวอักษร ASCII ตัวพิมพ์เล็ก, ตัวเลข, ., _, -, ความยาว 1–64 ตัวอักษร) ตัวอย่างเช่น autonomous agent สามารถตั้งค่านี้เป็นตัวระบุเฟรมเวิร์กหรือรันไทม์ของตนเองได้ (เช่น my-agent.v1) ค่าที่ไม่เป็นไปตามข้อกำหนด (รวมถึงตัวพิมพ์ใหญ่, สตริงว่าง, ความยาวเกิน หรืออักขระที่ไม่รองรับ) จะส่งคืน HTTP 400 invalid_request โดยไม่มีการแปลงตัวพิมพ์ และทำให้ไม่สามารถสร้างบัญชีได้ ให้ละเว้นหรือส่ง null เมื่อไม่ต้องการใช้งาน
    • referrer: URL ต้นทางหรือสตริงชื่อโฮสต์ โดยเฉพาะประเภทที่ไม่ใช่สตริงเท่านั้นที่จะส่งคืน HTTP 400

การส่งฟิลด์ที่ไม่ได้กำหนดไว้ เช่น signup_method จะส่งคืน HTTP 400 invalid_request

Session token และ API key

วงจรชีวิตของ Session token

  • รูปแบบ: rgs_ ตามด้วยอักขระเลขฐานสิบหกตัวพิมพ์เล็ก 64 ตัว
  • อายุการใช้งาน: อายุการใช้งานสูงสุด 7 วัน และจะหมดอายุโดยอัตโนมัติหลังจากไม่มีการใช้งานเป็นเวลา 24 ชั่วโมง
  • ไม่มี Refresh token: เมื่อ session token หมดอายุ ให้เริ่มขั้นตอน challenge และการเข้าสู่ระบบใหม่
  • ส่วนหัว: ส่ง session token ในส่วนหัวของคำขอ Authorization: Bearer rgs_...

การสร้าง API key

  • เรียก POST /keys พร้อม session token เพื่อสร้าง API key (rgw_ ตามด้วยอักขระเลขฐานสิบหก 64 ตัว)
  • แต่ละบัญชีสามารถมีคีย์ที่ยังไม่ถูกเพิกถอนและยังไม่หมดอายุ (active + disabled) ได้สูงสุด 20 คีย์ โดยคีย์ที่หมดอายุแล้วจะไม่ถูกนับ หากเกินจำนวนนี้จะส่งคืน HTTP 409 key_limit_reached พร้อม reason: active_keys และ limit: 20 โปรดเพิกถอนคีย์ก่อน ขีดจำกัดนี้มีผลครอบคลุมทุกข้อมูลระบุตัวตน, เซสชัน และเชนทั้งหมดของบัญชี นอกจากนี้ การสร้างและการสลับคีย์ยังจำกัดอยู่ที่ 20 ครั้งต่อ 24 ชั่วโมง หากเกินจะส่งคืน HTTP 429 rate_limited พร้อม Retry-After: 3600
  • เพดานและวันหมดอายุที่ไม่บังคับ: คุณสามารถระบุ cu_cap (เพดาน CU ตลอดอายุการใช้งานสำหรับคีย์ ซึ่งเป็น soft cap) และวันหมดอายุ (expires_in_secs หรือ expires_at สูงสุดไม่เกินจำนวนวันที่นโยบายคีย์อนุญาต) เมื่อหมดอายุหรือเพดานหมดลง เซิร์ฟเวอร์จะส่งคืน 403 (JSON-RPC -32025, reason key_expired หรือ key_cap_exhausted)
  • ค่าความลับ api_key จะ แสดงเพียงครั้งเดียวเมื่อสร้าง โปรดจัดเก็บอย่างปลอดภัยทันทีใน secrets manager หรือตัวแปรสภาพแวดล้อมของคุณ
  • API key เดียวสามารถใช้งานได้กับทุกเชนที่รองรับทั้งบน JSON-RPC และ Data API

ทำ Session หรือ API key หายใช่ไหม?

ใน BlockVectra ข้อมูลระบุตัวตนของบัญชี agent จะผูกกับที่อยู่กระเป๋าเงิน Ethereum ที่ใช้ระหว่างการลงทะเบียน หาก session token ของคุณหมดอายุ หรือ API key สูญหายหรือรั่วไหล คุณสามารถกู้คืนการควบคุมทั้งหมดได้โดยใช้กระเป๋าเงินนั้นเพียงอย่างเดียว:

  1. ยืนยันตัวตนใหม่ด้วยกระเป๋าเงินเดิม: ขอ challenge, ลงนามด้วยกระเป๋าเงินเดิม และส่งคำขอเข้าสู่ระบบ (POST /auth/siwe/login) เซิร์ฟเวอร์จะตรวจสอบลายเซ็น, เข้าสู่ระบบบัญชีเดิมที่มีอยู่โดยส่ง account_created: false และออก session token ใหม่ให้
  2. สร้าง API key ใหม่: เมื่อได้ session token ใหม่แล้ว ให้เรียก POST /keys พร้อม {"label": "..."} และส่วนหัว Authorization: Bearer <token> endpoint จะส่งคืน HTTP 201 พร้อมรายละเอียดคีย์ที่สร้างขึ้นใน key และค่าความลับที่แสดงครั้งเดียวใน api_key บันทึกคีย์นี้ในตัวแปรสภาพแวดล้อมหรือ secrets manager ของคุณทันที
  3. แสดงรายการคีย์ทั้งหมดของบัญชี:
    • Endpoint: GET /keys
    • ส่วนหัว: Authorization: Bearer <token>
    • พารามิเตอร์ Query: ไม่บังคับ include_revoked=true (เมื่อเป็น true จะรวมคีย์ที่ถูกเพิกถอนด้วย ค่าเริ่มต้นคือเฉพาะคีย์ที่ active/disabled เท่านั้น)
    • การตอบกลับ: HTTP 200 พร้อม JSON {"items": [...]} แต่ละองค์ประกอบในอาร์เรย์ items ประกอบด้วย:
      • key_id: ตัวระบุคีย์ที่ไม่ซ้ำกัน (สตริง)
      • label: ป้ายกำกับของคีย์ (สตริงหรือ null)
      • status: สถานะ ("active", "disabled" หรือ "revoked")
      • created_at: เวลาที่สร้าง (สตริง ISO 8601)
      • revoked_at: เวลาที่เพิกถอน (สตริง หรือ null หากยังไม่ถูกเพิกถอน)
  4. เพิกถอนคีย์ที่ไม่ได้ใช้หรือคีย์ที่ถูกบุกรุก:
    • Endpoint: POST /keys/{key_id}/revoke (หมายเหตุ: ใช้ POST พร้อมระบุ key_id เป้าหมายในพาธ โดยเนื้อหาคำขอว่างเปล่า)
    • ส่วนหัว: Authorization: Bearer <token>
    • พฤติกรรม: idempotent คีย์ที่มีสถานะ active หรือ disabled สามารถเพิกถอนได้ทั้งคู่ หากถูกเพิกถอนอยู่แล้วจะส่งคืน HTTP 200 โดยไม่เปลี่ยนแปลง หลังจากการเพิกถอน คำขอที่ใช้คีย์นั้นจะถูกปฏิเสธ
    • การตอบกลับ: HTTP 200 ส่งคืนออบเจกต์ของคีย์ที่ถูกเพิกถอน (ฟิลด์ตรงกับออบเจกต์คีย์ด้านบน โดยมี status: "revoked" และการประทับเวลาใน revoked_at)

ความปลอดภัยของคีย์และข้อมูลลับ

จัดเก็บ private key ของกระเป๋าเงินและ API key ไว้ในตัวแปรสภาพแวดล้อมหรือ secrets manager ห้ามคอมมิตลงในที่เก็บโค้ด, เขียนลงใน log หรือวางลงในบทสนทนากับ AI โดยเด็ดขาด

คำแนะนำด้านความปลอดภัย

  • ใช้คีย์ระยะสั้นและเพิกถอนเมื่อเสร็จสิ้น: สำหรับงานอัตโนมัติหรืองานชั่วคราว ให้สร้างคีย์ที่มีอายุสั้นด้วย expires_in_secs และเพิกถอนทันทีผ่าน POST /keys/{key_id}/revoke เมื่องานเสร็จสิ้น

ขีดจำกัดอัตราการลงทะเบียน (signup_rate_limited)

การสร้างบัญชีอยู่ภายใต้ขีดจำกัดอัตราการลงทะเบียน โดย token bucket ต่อ IP มีความจุ 100 บัญชี และเติมใหม่ในอัตรา 100 บัญชี/ชั่วโมง ต่อที่อยู่ IPv4 หรือคำนำหน้า IPv6 /64 ซึ่งแชร์ร่วมกันระหว่างการลงทะเบียนผ่าน SIWE และ OAuth:

  • เมื่อเกินขีดจำกัดการลงทะเบียน POST /auth/siwe/login จะส่งคืน HTTP 429 signup_rate_limited พร้อมส่วนหัว Retry-After ที่ระบุจำนวนวินาทีที่ต้องรอ
  • ฟิลด์ reason จะจำแนกขอบเขตของขีดจำกัด:
    • per_ip: งบประมาณการลงทะเบียนสำหรับคำนำหน้า IP ที่ส่งคำขอหมดลงแล้ว
    • global: ขีดจำกัดการลงทะเบียนรวมทั้งแพลตฟอร์มหมดลงแล้ว
  • ขีดจำกัดอัตราการลงทะเบียนจะประเมินเฉพาะการลงทะเบียนบัญชีใหม่เท่านั้น บัญชีที่มีอยู่แล้วซึ่งเข้าสู่ระบบจะไม่ถูกบล็อกโดยขีดจำกัดอัตราการลงทะเบียน

ขั้นตอนถัดไป

อัปเดตล่าสุด:

ในหน้านี้