Đăng ký bằng lập trình: đăng nhập bằng ví và tạo API key cho Agent và CI

Đăng ký và tạo API key bằng lập trình qua chữ ký ví Ethereum (EIP-191), không cần trình duyệt, cho AI Agent, script và quy trình CI.

Đối với AI Agent tự chủ, pipeline CI và script tự động chạy không cần trình duyệt, BlockVectra cung cấp quy trình đăng nhập và mở tài khoản bằng lập trình dựa trên chữ ký ví Ethereum (EIP-4361 / EIP-191).

Key security

Không bao giờ dán khóa riêng, session token hoặc API key vào cuộc trò chuyện với AI hay truyền chúng dưới dạng đối số công cụ MCP.

Trước khi đăng ký, bạn có thể thử endpoint công khai không cần API key https://api.blockvectra.com/v1/robinhood_mainnet/public (chỉ các phương thức JSON-RPC dành cho ví, Data API cần API key; phương thức và giới hạn theo /v1/chains); đăng ký tài khoản nếu hạn mức không đủ.

Tổng quan quy trình

Quy trình đăng ký và cấp API key bằng lập trình gồm bốn bước:

  1. Yêu cầu challenge: Gửi yêu cầu tới POST /auth/siwe/challenge để lấy thông điệp đăng nhập do máy chủ tạo.
  2. Ký thông điệp: Ký chính xác thông điệp bằng ví Ethereum EOA qua EIP-191 (personal_sign).
  3. Đăng nhập / mở tài khoản: Gửi nguyên văn thông điệp và chữ ký tới POST /auth/siwe/login. Khi ví đăng nhập lần đầu, tài khoản được tạo tự động (account_created: true). Tài khoản mới nhận 30,000,000 CU khi đăng ký — không cần thẻ tín dụng.
  4. Tạo API key: Dùng session token để gọi POST /keys và tạo API key.

Ví dụ đầy đủ có thể chạy

Bắt đầu tại đây: dùng bộ ký Ethereum EOA cục bộ, tạo API key và xác minh bằng eth_blockNumber. Ví dụ Bash cần curl, jq và Foundry cast. Giữ thông tin xác thực ví trong môi trường ký cục bộ của bạn.

Mẫu khởi đầu đầy đủ: blockvectra/agent-quickstart

Các script sau đọc thông tin xác thực ví, hoàn tất chuỗi challenge và đăng nhập, cấp API key, xuất hoặc in export BLOCKVECTRA_API_KEY=... để cấu hình môi trường, rồi gửi yêu cầu eth_blockNumber để xác minh:

API key mới cần vài giây để có hiệu lực; các ví dụ này tự động thử lại.

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 cơ sở và chế độ lập trình

Tất cả endpoint xác thực và quản lý API key dùng URL cơ sở chính thức:

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

Bỏ header Origin

Yêu cầu bằng lập trình hoạt động trong chế độ lập trình:

  • Cả yêu cầu challenge (POST /auth/siwe/challenge) và đăng nhập (POST /auth/siwe/login) đều không được chứa header Origin (curl và HTTP client tiêu chuẩn mặc định bỏ header này; không thêm thủ công).
  • Nếu gửi header Origin nhưng giá trị không phải miền bảng điều khiển web đã cấu hình (kể cả chuỗi rỗng hoặc null), yêu cầu challenge trả HTTP 400 invalid_request.
  • Nếu chế độ khi đăng nhập không khớp chế độ challenge (ví dụ yêu cầu challenge bằng lập trình không có Origin, sau đó gửi đăng nhập có header Origin, hoặc ngược lại), yêu cầu đăng nhập trả HTTP 400 siwe_invalid với reason: domain_mismatch.

Tính toàn vẹn thông điệp và yêu cầu đối với ví

  • Ký và gửi nguyên văn: Client phải ký và gửi văn bản thông điệp chính xác như endpoint challenge trả về. Không thay đổi khoảng trắng, miền, Chain ID hay bất kỳ trường nào. Mọi thay đổi đều dẫn đến HTTP 400 siwe_invalid với reason: signature.
  • Ví được hỗ trợ: Tài khoản do cá nhân sở hữu (EOA) trên Ethereum mainnet (Chain ID 1). Chữ ký phải là chữ ký ECDSA 65 byte (personal_sign). Không hỗ trợ ví hợp đồng (EIP-1271) và tài khoản thông minh.
  • Hiệu lực challenge: Mỗi nonce challenge chỉ dùng một lần và hết hạn sau 5 phút.

Body yêu cầu và nguồn đăng ký (tùy chọn)

Body yêu cầu POST /auth/siwe/login chấp nhận tham số xác thực bắt buộc và các trường nguồn đăng ký tùy chọn:

  • Trường bắt buộc:
    • message: Chuỗi thông điệp SIWE đầy đủ lấy từ endpoint challenge.
    • signature: Chữ ký thập lục phân 65 byte (có tiền tố 0x) tạo bằng cách ký message qua EIP-191 bằng ví Ethereum.
  • Trường nguồn đăng ký tùy chọn (chỉ lưu một lần khi tạo tài khoản mới; bỏ qua trong các lần đăng nhập sau):
    • ref: Token kênh viết thường khớp ^[a-z0-9._-]{1,64}$ (chữ cái ASCII viết thường, chữ số, ., _, -, 1–64 ký tự). Ví dụ, Agent tự chủ có thể đặt giá trị này thành mã định danh framework hoặc runtime (như my-agent.v1). Giá trị không hợp lệ (gồm chữ hoa, chuỗi rỗng, quá dài hoặc ký tự không được hỗ trợ) trả HTTP 400 invalid_request mà không chuyển đổi chữ hoa thành chữ thường và ngăn tạo tài khoản; bỏ qua hoặc truyền null nếu không áp dụng.
    • referrer: Chuỗi URL nguồn hoặc hostname; chỉ kiểu không phải chuỗi mới trả HTTP 400.

Gửi trường chưa được định nghĩa như signup_method trả HTTP 400 invalid_request.

Session token và API key

Vòng đời session token

  • Định dạng: rgs_ theo sau bởi 64 ký tự thập lục phân viết thường.
  • Hiệu lực: Thời gian tồn tại tuyệt đối là 7 ngày; tự động hết hạn sau 24 giờ không hoạt động.
  • Không có refresh token: Khi session token hết hạn, bắt đầu quy trình challenge và đăng nhập mới.
  • Header: Truyền session token trong header yêu cầu Authorization: Bearer rgs_....

Tạo API key

  • Gọi POST /keys bằng session token để tạo API key (rgw_ theo sau bởi 64 ký tự thập lục phân).
  • Mỗi tài khoản có tối đa 20 API key chưa bị thu hồi và chưa hết hạn (active + disabled); API key hết hạn không được tính. Vượt giới hạn trả HTTP 409 key_limit_reached với reason: active_keys và limit: 20; hãy thu hồi một API key trước. Giới hạn áp dụng trên tất cả danh tính, phiên và chuỗi của tài khoản. Tạo và xoay vòng API key cũng bị giới hạn ở 20 lần mỗi 24 giờ; vượt giới hạn trả HTTP 429 rate_limited với Retry-After: 3600.
  • Hạn mức và thời hạn tùy chọn: bạn có thể cung cấp cu_cap (hạn mức CU trọn đời của API key, là hạn mức mềm) và thời hạn (expires_in_secs hoặc expires_at, tối đa số ngày chính sách API key cho phép); khi hết hạn hoặc dùng hết hạn mức, máy chủ trả 403 (JSON-RPC -32025, reason là key_expired hoặc key_cap_exhausted).
  • Giá trị bí mật api_key chỉ được trả một lần khi tạo. Lưu an toàn ngay vào trình quản lý bí mật hoặc biến môi trường.
  • Một API key hoạt động trên tất cả chuỗi được hỗ trợ cho JSON-RPC và Data API.

Mất session token hoặc API key?

Trong BlockVectra, danh tính tài khoản của Agent gắn với địa chỉ ví Ethereum dùng khi đăng ký. Nếu session token hết hạn hoặc API key bị mất hay lộ, bạn có thể khôi phục toàn quyền kiểm soát chỉ bằng ví đó:

  1. Xác thực lại bằng cùng ví: Yêu cầu challenge, ký bằng cùng ví và gửi yêu cầu đăng nhập (POST /auth/siwe/login). Máy chủ xác minh chữ ký, đăng nhập tài khoản hiện có với account_created: false và cấp session token mới.
  2. Tạo API key mới: Dùng session token mới để gọi POST /keys với {"label": "..."} và header Authorization: Bearer <token>. Endpoint trả HTTP 201 với chi tiết API key đã tạo trong key và giá trị bí mật chỉ trả một lần trong api_key. Lưu API key này ngay vào biến môi trường hoặc trình quản lý bí mật.
  3. Liệt kê tất cả API key của tài khoản:
    • Endpoint: GET /keys
    • Header: Authorization: Bearer <token>
    • Tham số truy vấn: include_revoked=true tùy chọn (khi là true, bao gồm API key đã thu hồi; mặc định chỉ gồm API key active/disabled).
    • Phản hồi: HTTP 200 với JSON {"items": [...]}. Mỗi phần tử trong mảng items gồm:
      • key_id: mã định danh API key duy nhất (chuỗi)
      • label: nhãn API key (chuỗi hoặc null)
      • status: trạng thái ("active", "disabled" hoặc "revoked")
      • created_at: dấu thời gian tạo (chuỗi ISO 8601)
      • revoked_at: dấu thời gian thu hồi (chuỗi, hoặc null nếu chưa thu hồi)
  4. Thu hồi API key không dùng hoặc bị lộ:
    • Endpoint: POST /keys/{key_id}/revoke (lưu ý: dùng POST với key_id đích trong đường dẫn; body yêu cầu rỗng)
    • Header: Authorization: Bearer <token>
    • Hành vi: lũy đẳng; API key ở trạng thái active hoặc disabled đều có thể thu hồi. Nếu đã thu hồi, trả HTTP 200 và không thay đổi. Sau khi thu hồi, yêu cầu dùng API key đó bị từ chối.
    • Phản hồi: HTTP 200 trả đối tượng API key đã thu hồi (các trường khớp đối tượng API key ở trên, với status: "revoked" và dấu thời gian trong revoked_at).

Key and secret security

Lưu khóa riêng của ví và API key trong biến môi trường hoặc trình quản lý bí mật. Không bao giờ commit chúng vào kho mã, ghi vào log hay dán vào cuộc trò chuyện với AI.

Khuyến nghị bảo mật

  • Dùng API key ngắn hạn và thu hồi khi hoàn tất: Với tác vụ tự động hoặc tạm thời, tạo API key ngắn hạn bằng expires_in_secs và thu hồi ngay qua POST /keys/{key_id}/revoke khi hoàn tất công việc.

Giới hạn tốc độ đăng ký (signup_rate_limited)

Việc tạo tài khoản chịu giới hạn tốc độ đăng ký. Token bucket mỗi IP có dung lượng 100 tài khoản và nạp lại 100 tài khoản/giờ cho mỗi địa chỉ IPv4 hoặc tiền tố IPv6 /64, dùng chung cho đăng ký SIWE và OAuth:

  • Khi vượt giới hạn đăng ký, POST /auth/siwe/login trả HTTP 429 signup_rate_limited với header Retry-After cho biết số giây cần chờ.
  • Trường reason phân biệt phạm vi giới hạn:
    • per_ip: hạn mức đăng ký của tiền tố IP yêu cầu đã cạn.
    • global: giới hạn đăng ký tổng hợp của nền tảng đã cạn.
  • Giới hạn tốc độ đăng ký chỉ áp dụng cho đăng ký tài khoản mới. Tài khoản hiện có đăng nhập không bị chặn bởi giới hạn tốc độ đăng ký.

Các bước tiếp theo

Cập nhật lần cuối:

Trên trang này