Used to check for browser translation.
用于检测浏览器翻译。
ブラウザの翻訳を検出する
How-to Guides

Request a Signature


One of the most common tasks in a decentralized application is asking a user to sign a piece of data. This could be to authorize a transaction, confirm terms of service, or simply to prove control over their DID. The did-auth library simplifies this process using the signature claim.

This guide will walk you through how to request a signature for both a simple message and an on-chain transaction.

How It Works#

The signature process involves your application, the did-auth SDK, and the user's DID Wallet. The wallet acts as a remote signer, ensuring the user's private key never leaves their device.

Here is the typical flow:

UserDID WalletYour App BackendBrowser/ClientUserDID WalletYour App BackendBrowser/ClientInitiate authenticationSend auth URL for QR codeScan QR code with auth URLRequest claims (onConnect is triggered)Respond with 'signature' claim request"Do you want to sign this message?"ApproveSend signed data and proof backVerify signature and claimsSignal successful login

Requesting a Message Signature#

Let's start with the simplest case: asking a user to sign a plain text message. You'll define this request within the onConnect handler of your WalletHandlers configuration.

const { WalletAuthenticator, WalletHandlers } = require('@arcblock/did-auth');

const authenticator = new WalletAuthenticator({
wallet: 'z1....',
appInfo: { /* ... */ },
});

const handlers = new WalletHandlers({
authenticator,
tokenStorage,
onConnect: async ({ claims }) => {
// Request a signature on a simple text message
claims.push({
type: 'signature',
description: 'Please sign this message to confirm your identity.',
typeUrl: 'mime:text/plain',
data: 'This is a test message from our application.',
});
},
// ... other handlers
});

// In your Express app
// app.use('/api/did/auth', handlers);

In this example, when a user scans the QR code, their wallet will prompt them to sign the string "This is a test message from our application.". After they approve, the signature will be sent back to your application for verification.

Requesting a Transaction Signature#

Requesting a signature for an on-chain transaction follows the same pattern but requires more specific information, such as the transaction type and its payload. You have two primary ways to do this.

Option 1: Provide a Raw Transaction Object (Recommended)#

You can provide a standard JavaScript object representing the transaction. The did-auth library will automatically encode it for you based on the chainInfo you provided to the WalletAuthenticator.

const handlers = new WalletHandlers({
authenticator,
tokenStorage,
onConnect: async ({ claims, userDid, userPk }) => {
// Request signature for a raw transaction object
claims.push({
type: 'signature',
description: 'Please sign this transaction to transfer 100 tokens.',
typeUrl: 'TransferV2Tx', // Specific transaction type for the target chain
data: {
from: userDid, // The user's DID
pk: userPk, // The user's public key
itx: {
to: 'z1d...',
tokens: [
{
address: 'z35nB2SA6xxBuoaiuUXUw6Gah2SNU3UzqdgEt',
value: '100',
},
],
},
},
// Optionally, specify requirements for the signature
requirement: {
tokens: [
{
address: 'z35nB2SA6xxBuoaiuUXUw6Gah2SNU3UzqdgEt',
value: '100',
},
],
},
});
},
// ... other handlers
});

Option 2: Provide a Pre-Encoded Transaction#

For more control, you can encode the transaction yourself using a library like @ocap/client and provide the resulting buffer as a Base58 string. This is useful if your encoding logic is complex or managed elsewhere.

const Client = require('@ocap/client');
const { toBase58 } = require('@ocap/util');
const { fromPublicKey } = require('@ocap/wallet');

const client = new Client('https://beta.abtnetwork.io/api');

const handlers = new WalletHandlers({
authenticator,
tokenStorage,
onConnect: async ({ claims, userDid, userPk }) => {
// 1. Encode the transaction first
const { buffer: encodedTx } = await client.encodeTransferV2Tx({
tx: { /* ... transaction data from Option 1 ... */ },
wallet: fromPublicKey(userPk),
});

// 2. Request signature for the encoded transaction buffer
claims.push({
type: 'signature',
description: 'Please sign this pre-encoded transaction.',
typeUrl: 'fg:t:transaction', // Generic type for any encoded transaction
origin: toBase58(encodedTx), // Pass the encoded buffer as a Base58 string
requirement: { /* ... */ },
});
},
// ... other handlers
});

Key Parameters for Signature Claims#

The signature claim has several configurable parameters to meet different needs.

Parameter

Type

Description

typeUrl

string

Required. The type of data to be signed. E.g., mime:text/plain, fg:t:transaction, or a specific transaction type like TransferV2Tx.

description

string

A human-readable description of the signature request, shown to the user in the wallet. Defaults to a standard message.

data

string or object

The content to be signed. For mime:* types, this is the raw string. For transaction types like TransferV2Tx, this is the raw transaction object.

origin

string

Used for pre-encoded data. For fg:t:transaction, this should be the Base58-encoded transaction buffer.

display

string

A JSON string for displaying rich content in the wallet's UI, such as a URL or structured text.

method

string

Hashing algorithm to use before signing. Defaults to sha3. Set to none to sign the raw data without hashing.

nonce

string

An optional random string to associate with the signature request, useful for preventing replay attacks.

requirement

object

An optional object specifying tokens or assets the user must possess to complete the signature.


Now that you know how to request signatures, you can build more complex workflows. To learn how to chain multiple requests together, proceed to the Handle Multiple Workflows guide. For a complete list of all claim types and their parameters, refer to the Schemas documentation.