Document Signing
requestSignature() asks the user's credential wallet to sign
a document hash. The wallet shows a consent popup; the user approves or
rejects. No private key ever leaves the wallet.
SignRequest
TypeScript
interface SignRequest { hash: string // Hex-encoded file hash fileName: string // Original file name (displayed to user) hashAlgorithm: string // 'SHA-256' | 'SHA-384' | 'SHA-512' fileSize: number // File size in bytes }
SignResponse
TypeScript
interface SignResponse { approved: boolean // Whether the user approved did: string // Signer's DID signature: string // Base64url-encoded signature publicKeyJwk: JsonWebKey // Public key for verification timestamp: string // ISO 8601 timestamp storeToken: string // Opaque token for anchoring }
Nonce-based CustomEvent Pattern
Each signing request generates a unique nonce. The wallet extension listens
for sign-request CustomEvents and responds on
sign-response with the matching nonce. This prevents replay
and cross-tab interference.
User Consent
The wallet extension displays a popup showing the file name, hash
algorithm, file size, and the requesting origin. The user must explicitly
approve before any signature is produced. If the user rejects,
approved is false and all other fields are
undefined.
Full Example
TypeScript
import { pickWallet, requestSignature } from '@attestto/id-wallet-adapter' // 1. Hash the file const file = document.querySelector('input[type=file]').files[0] const buffer = await file.arrayBuffer() const hashBuffer = await crypto.subtle.digest('SHA-256', buffer) const hash = [...new Uint8Array(hashBuffer)] .map(b => b.toString(16).padStart(2, '0')) .join('') // 2. Pick a wallet const wallet = await pickWallet({ render: 'modal' }) // 3. Request signature const response = await requestSignature(wallet, { hash, fileName: file.name, hashAlgorithm: 'SHA-256', fileSize: file.size, }) // 4. Verify the response if (response.approved) { console.log('Signed by:', response.did) console.log('Signature:', response.signature) }