Skip to main content
Signing is a critical step that proves you have authority to execute the operations in a transaction. WAX supports multiple signing providers for different use cases.

Understanding signatures

Every transaction must be signed with one or more private keys that correspond to the authorities required by the operations in the transaction.
1

Check required authorities

Before signing, determine which authorities are needed for your transaction.
const authorities = tx.requiredAuthorities;

console.log('Posting accounts:', Array.from(authorities.posting));
console.log('Active accounts:', Array.from(authorities.active));
console.log('Owner accounts:', Array.from(authorities.owner));
console.log('Other authorities:', authorities.other);
Most operations require posting authority (votes, comments). Financial operations require active authority (transfers, power ups). Account recovery requires owner authority.
2

Get the signature digest

The signature digest is what you actually sign. It’s a cryptographic hash of the transaction.
// Get signature digest for HF26+ serialization
const sigDigest = tx.sigDigest;
console.log('Signature digest:', sigDigest);

// Get legacy signature digest (pre-HF26)
const legacySigDigest = tx.legacy_sigDigest;
3

Sign with a provider

Use your preferred signing provider to sign the transaction. See the sections below for provider-specific examples.
4

Verify signatures

After signing, you can verify which public keys signed the transaction.
// Get public keys that signed the transaction
const signerKeys = tx.signatureKeys;
console.log('Signers:', signerKeys);

// Check if transaction is signed
if (tx.isSigned()) {
  console.log('Transaction has signatures');
}

Signing with Beekeeper

Beekeeper is the official wallet solution for Hive. It provides secure key management and signing.
import { createHiveChain } from '@hiveio/wax';
import beekeeperFactory from '@hiveio/beekeeper';

async function signWithBeekeeper() {
  // Initialize Beekeeper
  const beekeeper = await beekeeperFactory();
  const session = beekeeper.createSession('my-app-salt');

  // Create wallet
  const { wallet } = await session.createWallet('my-wallet');

  // Import private key
  const privateKey = '5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n';
  await wallet.importKey(privateKey);

  // Get public key
  const [publicKey] = wallet.getPublicKeys();

  // Create and sign transaction
  const chain = await createHiveChain();
  const tx = await chain.createTransaction();

  tx.pushOperation({
    vote_operation: {
      voter: "alice",
      author: "bob",
      permlink: "example-post",
      weight: 10000
    }
  });

  // Sign with Beekeeper wallet
  const signature = tx.sign(wallet, publicKey);
  console.log('Signature:', signature);

  return tx;
}
Beekeeper runs as a separate process and manages keys securely. Never hardcode private keys in production code.

Signing with Hive Keychain

Hive Keychain is a browser extension that provides secure signing for web applications.
import { createHiveChain } from '@hiveio/wax';
import { KeychainSigner } from '@hiveio/signers-keychain';

async function signWithKeychain() {
  // Initialize Keychain signer
  const signer = new KeychainSigner();

  // Create transaction
  const chain = await createHiveChain();
  const tx = await chain.createTransaction();

  tx.pushOperation({
    vote_operation: {
      voter: "alice",
      author: "bob",
      permlink: "example-post",
      weight: 10000
    }
  });

  // Sign with Keychain
  const signedTx = await signer.signTransaction(
    tx,
    "alice", // username
    "posting" // key type
  );

  console.log('Signed transaction:', signedTx);
  return signedTx;
}
Hive Keychain must be installed in the user’s browser. Always check if Keychain is available before attempting to sign.

Signing with MetaMask

MetaMask Snaps enables signing Hive transactions using MetaMask.
import { createHiveChain } from '@hiveio/wax';
import { MetaMaskSigner } from '@hiveio/signers-metamask';

async function signWithMetaMask() {
  // Initialize MetaMask signer
  const signer = new MetaMaskSigner();

  // Connect to MetaMask Snap
  await signer.connect();

  // Create transaction
  const chain = await createHiveChain();
  const tx = await chain.createTransaction();

  tx.pushOperation({
    transfer_operation: {
      from_account: "alice",
      to_account: "bob",
      amount: chain.hive.satoshis(1),
      memo: "Payment"
    }
  });

  // Sign with MetaMask
  const signedTx = await signer.signTransaction(tx, "alice");

  console.log('Signed with MetaMask:', signedTx);
  return signedTx;
}

Signing with PeakVault

PeakVault is a mobile wallet that supports signing through deep links.
import { createHiveChain } from '@hiveio/wax';
import { PeakVaultSigner } from '@hiveio/signers-peakvault';

async function signWithPeakVault() {
  // Initialize PeakVault signer
  const signer = new PeakVaultSigner({
    callbackUrl: 'myapp://signed' // Your app's deep link
  });

  // Create transaction
  const chain = await createHiveChain();
  const tx = await chain.createTransaction();

  tx.pushOperation({
    vote_operation: {
      voter: "alice",
      author: "bob",
      permlink: "example-post",
      weight: 10000
    }
  });

  // Sign with PeakVault (opens mobile app)
  const signedTx = await signer.signTransaction(tx, "alice");

  console.log('Signed with PeakVault:', signedTx);
  return signedTx;
}

Manual signing

You can also sign transactions manually if you have the private key.
import { createHiveChain } from '@hiveio/wax';

async function manualSign() {
  const chain = await createHiveChain();
  const tx = await chain.createTransaction();

  tx.pushOperation({
    vote_operation: {
      voter: "alice",
      author: "bob",
      permlink: "example-post",
      weight: 10000
    }
  });

  // Get signature digest
  const digest = tx.sigDigest;

  // Sign with your signing method
  const signature = yourSigningFunction(digest, privateKey);

  // Add signature to transaction
  tx.addSignature(signature);

  return tx;
}
Be extremely careful when handling private keys directly. Never expose them in client-side code or logs.

Multi-signature transactions

Some operations require multiple signatures from different authorities.
import { createHiveChain } from '@hiveio/wax';
import beekeeperFactory from '@hiveio/beekeeper';

async function multiSigTransaction() {
  const beekeeper = await beekeeperFactory();
  const session = beekeeper.createSession('multi-sig');

  // Create two wallets with different keys
  const { wallet: wallet1 } = await session.createWallet('wallet1');
  await wallet1.importKey(privateKey1);
  const [pubKey1] = wallet1.getPublicKeys();

  const { wallet: wallet2 } = await session.createWallet('wallet2');
  await wallet2.importKey(privateKey2);
  const [pubKey2] = wallet2.getPublicKeys();

  // Create transaction requiring multiple signatures
  const chain = await createHiveChain();
  const tx = await chain.createTransaction();

  tx.pushOperation({
    // Operation requiring multiple authorities
    account_update_operation: {
      account: "alice",
      // ... account update details
    }
  });

  // Sign with first wallet
  tx.sign(wallet1, pubKey1);

  // Sign with second wallet
  tx.sign(wallet2, pubKey2);

  console.log('Multi-sig transaction signed');
  console.log('Signatures:', tx.transaction.signatures);

  return tx;
}

Best practices

Always validate your transaction before attempting to sign it. This catches errors early and prevents wasted signing attempts.
tx.validate();
const signature = tx.sign(wallet, publicKey);
Before signing, verify that you have the correct authority level for the operations in your transaction.
const authorities = tx.requiredAuthorities;
if (authorities.active.size > 0) {
  console.log('This transaction requires active authority');
}
Signing can fail for various reasons (user rejection, wrong key, etc.). Always handle errors appropriately.
try {
  const signature = await tx.sign(wallet, publicKey);
} catch (error) {
  if (error.message.includes('user rejected')) {
    console.log('User cancelled signing');
  } else {
    console.error('Signing failed:', error);
  }
}
Private keys should never be:
  • Hardcoded in source code (except for testing)
  • Logged to console or files
  • Sent over insecure connections
  • Stored in plaintext
Use secure signing providers like Beekeeper or Keychain instead.

Next steps

Broadcasting transactions

Learn how to broadcast your signed transactions

Signing providers

Explore all available signing provider extensions

Beekeeper setup

Detailed guide to using Beekeeper

Keychain integration

Integrate Hive Keychain in your web app

Build docs developers (and LLMs) love