Skip to content

Auth 登录 ​

Auth 签名证明用户持有钱包身份私钥。它不是 BTC 地址或 Lightning 节点所有权证明,也不会直接建立业务登录会话。当前身份签名仅支持 regtest;新接入优先使用 V2。

V2 请求与响应 ​

请求结构 ​

ts
interface AuthSignatureRequestV2 {
  signature_version: 2
  challenge_id: string
  nonce: string
  network: Network
  client_id: string
  purpose: 'login'
  wallet_type: 'stashwallet'
  timestamp: number
  expires_at: number
  origin?: string
}

origin 在请求类型中可选,但后端签发和验签上下文必须包含正确来源。

字段约束 ​

  • challenge_id:32 位小写十六进制。
  • nonce:64 位小写十六进制,由后端安全随机生成。
  • timestamp、expires_at:Unix 秒,必须为安全整数。
  • client_id:1–64 字符,首位为字母或数字,之后允许字母、数字、点、下划线、连字符。
  • challenge 有效期最多 120 秒;expires_at > timestamp。

后端应返回完整且经过校验的 V2 challenge。以下示例中的后端函数由业务方实现,不属于 SDK:

ts
import type { AuthSignatureRequestV2 } from 'stash-wallet-sdk'

async function login(
  client: import('stash-wallet-sdk').StashWalletClient,
  fetchChallenge: () => Promise<AuthSignatureRequestV2>,
  verifyOnBackend: (
    challenge: AuthSignatureRequestV2,
    signed: import('stash-wallet-sdk').AuthSignatureResponse,
  ) => Promise<void>,
) {
  const caps = await client.getCapabilities()
  const { network } = await client.getNetwork()
  if (!caps.canAuthSign || !caps.authNetworks.includes(network)) {
    throw new Error('Auth signing is unavailable')
  }
  const challenge = await fetchChallenge()
  if (challenge.network !== network) throw new Error('Network mismatch')
  const signed = await client.requestAuthSignature(challenge)
  await verifyOnBackend(challenge, signed)
}

响应字段 ​

  • 身份公钥:auth_pubkey,66 位 hex 压缩 secp256k1 公钥。
  • 签名:signature,128 位 hex compact r || s 签名。
  • 协议与挑战:signature_version、challenge_id、message。
  • 绑定信息:btc_address、node_id。
V2 响应上下文

client_id、purpose、wallet_type、network、timestamp、expires_at 在公共响应类型中为可选。V2 验证时必须核对必需上下文,不能自动降级接受 V1。

空 btc_address / node_id 表示未绑定;非空也不能仅凭 Auth 身份签名当作独立的地址或节点所有权证明。

规范消息与后端验证 ​

V2 规范消息为:

text
RGBS-AUTH-V2|{challenge_id}|{nonce}|{origin}|{network}|{wallet_type}|{client_id}|{purpose}|{timestamp}|{expires_at}

可从无浏览器副作用的协议入口导入辅助函数:

ts
import { buildAuthV2Message, validateAuthV2Context } from 'stash-wallet-sdk/protocol'
import type { AuthV2Context } from 'stash-wallet-sdk/protocol'

function canonicalMessage(context: AuthV2Context, expectedOrigin: string): string {
  validateAuthV2Context(context, expectedOrigin)
  return buildAuthV2Message(context)
}

validateAuthV2Context() 检查格式、origin、时间窗口与 client ID;buildAuthV2Message() 负责消息拼接和基本格式检查。它们不执行 ECDSA 验签,也不存储或消费 challenge。 服务端还必须:

  1. 从服务端保存的 challenge 重建上下文,不信任网页提交的 message、origin 或时间。
  2. 核对版本、用途、钱包类型、网络、client ID 与服务端允许值。
  3. 拒绝过期、未来签发、已使用或不匹配的 challenge。
  4. 按钱包实际签名算法验证 compact secp256k1 签名,不能只检查字符串格式。
  5. 验证成功后原子地消费 challenge,防止重放;再建立业务会话。

client_id 等公共元数据本身不是业务客户端真实性证明。JWT、邀请名单、节点权限与可信地址准入由业务方处理。

V1 兼容 ​

V1 请求必须显式提供 signature_version: 1、challenge_id、nonce、network,可选 origin。buildCanonicalMessage(challengeId, nonce, origin, network) 生成 RGBS-AUTH-V1|… 消息。

AUTH_PROTOCOL_VERSION / AUTH_MESSAGE_PREFIX 当前仍对应 V1,不能用来生成 V2 消息。AUTH_KDF_* 是旧 passphrase 路径兼容常量,不是要求业务网站派生或获取用户身份私钥。新接入不要采用旧 KDF 建立网站身份。

参数错误 ​

requestAuthSignature() 在发送前调用 assertAuthSignatureRequest()。参数错误可能抛出普通 Error('INVALID_PARAMETER'),而非 TransportError。SDK 的请求检查不是后端验证的替代品。参见 错误与兼容性。

交易并保护您的 RGB 资产 | 释放 RGB 协议的全部潜力