Sign a Message
Message signing is how a wallet proves ownership of an address. In the context of ERC-4337, every UserOperation must be signed by the wallet’s owner before the bundler will accept it.
signMessage() opens the widget, shows the user a “Sign Request” screen, and — upon approval — calls AWS KMS to produce a 65-byte ECDSA signature.
Basic usage
Section titled “Basic usage”const { signature } = await auth.signMessage('0xdeadbeef...');The message parameter accepts:
- A hex string (
"0x...") - A
Uint8Array - A viem-compatible
{ raw: Uint8Array | string }object
Signing a UserOperation hash
Section titled “Signing a UserOperation hash”The most common use case is signing an ERC-4337 UserOperation hash before submitting it to a bundler:
// Compute the hash from a UserOperation (implementation depends on your SDK)const userOpHash = computeUserOpHash(userOp);
// Sign itconst { signature } = await auth.signMessage(userOpHash);
// Attach the signatureuserOp.signature = signature;Network label override
Section titled “Network label override”When the widget opens, it shows the network name in the signing approval screen. By default, it uses the network or chainId you set at construction. You can override it per-call:
const { signature } = await auth.signMessage(hash, 'Base');How the signing works
Section titled “How the signing works”The SDK normalizes incoming message formats to a 0x-prefixed hex string before passing it to the widget. The widget sends the hash to KMS, which signs it with the user’s private key and returns a 65-byte signature (r + s + v).
One important detail: when OxGasClient uses signing internally (for smart account UserOperations), it applies the EIP-191 prefix before sending the hash to KMS. This is because the smart contract’s validateUserOp function calls ECDSA.recover(userOpHash.toEthSignedMessageHash(), signature) — meaning the contract adds the prefix on-chain, so the SDK must match it off-chain.
If you’re using signMessage() directly for your own purposes, pass the exact hash you want signed without any prefix. KMS will sign it as-is.
Timeout
Section titled “Timeout”Signing waits up to 2 minutes for the user to approve or reject (configurable via signTimeout). If the user doesn’t respond, signMessage() rejects with a SigningTimeoutError.
Return value
Section titled “Return value”interface SignMessageResult { signature: `0x${string}`; // 65-byte ECDSA signature}Error handling
Section titled “Error handling”import { SigningRejectedError, SigningTimeoutError } from '0xgas-auth';
try { const { signature } = await auth.signMessage(hash);} catch (err) { if (err instanceof SigningRejectedError) { console.log('User rejected'); } else if (err instanceof SigningTimeoutError) { console.log('Timed out after', err.timeoutMs, 'ms'); }}