# spark\_signMessage

The `spark_signMessage` method lets your app request a **secure, hashed message signature** from the user’s Spark wallet.\
This method provides a safe way to verify ownership of a Spark address, authenticate a user, or prove intent **without exposing the wallet to raw arbitrary message signing attacks.**

## :closed\_lock\_with\_key: How It Works

To ensure signing security and prevent vulnerabilities with arbitrary data, Xverse implements a **hash-before-sign** scheme.\
When your app sends a message to be signed:

1. The raw message string is **UTF-8 decoded** into bytes.
2. The wallet computes the SHA-256 hash of the message bytes
3. The wallet signs the resulting hash with the user’s Spark identity key
4. The wallet returns **the message signature** to your app in base64 format

This prevents signature malleability and enforces minimum payload size, while aligning with the cryptographic standards used by **Spark** and **Flashnet**.

## Parameters

<table><thead><tr><th width="221">Request parameters</th><th>Description</th></tr></thead><tbody><tr><td><code>message</code></td><td>a string representing the UTF-8 message to sign</td></tr></tbody></table>

## Example

```ts
import { request } from "sats-connect";

const message = `Xverse / Spark — Sign-in Request
App: flashdex.example
Action: auth
Nonce: 6b6a7b2a-4e1b-4c2c-9f46-1f2b3d0a9e23
Issued At: 2025-10-22T09:31:12Z
Expires At: 2025-10-22T09:36:12Z
Chain: spark
Note: This does not move funds.`;

const res = await request("spark_signMessage", { message });
```

## What `spark_signMessage` does

When called, this method:

1. Prompts the user to review the message to sign with their Xverse wallet:

* **Title:** `Sign Message with Spark Wallet`
* **Message Preview:** The human-readable message (UTF-8 text)
* The user can confirm or cancel the signing request

2. Signs the message upon user approval, following the [signing procedure](#how-it-works)
3. Returns **the message signature** to your app in base64 format

### Response

#### ✅ Success

```ts
{
  signature: "3045022100..." // Spark signature of the message in base64 format
}
```

#### :x: Error

```ts
{
  errorCode: "SIGN-MESSAGE-001",
  message: "User rejected message signing" | "Invalid message format",
  requestId: "01HJZKFABCDEFGHJKLMNPQRSTVW"
}
```

### 🔍 Verifying the Signature on Your Backend

To verify the signature:

```ts
import { secp256k1 } from '@noble/curves/secp256k1.js';
import { base64, hex } from '@scure/base';

// convert UTF-8 string to bytes
const decodedMessage = new TextEncoder().encode(message);

// decode base64 encoded signature
const decodedSignature = base64.decode(response.result.signature);

// decode hex encoded public key (provided by wallet)
const decodedPublicKey = hex.decode(sparkPublicKey);

const isValid = secp256k1.verify(decodedSignature, decodedMessage, decodedPublicKey);
```

This ensures end-to-end consistency: the signature always corresponds to the deterministic SHA-256 hash of the message.

## ⚠️ Security Notes

* The wallet **never signs raw messages directly** — only hashed digests.
* The app must display or record the human-readable message alongside the signature for auditability.
* Avoid embedding sensitive data directly in the message body; instead, use authentication challenges or session tokens.
* SHA-256 is fixed as the canonical hash digest for this method to stay consistent with Spark’s on-chain cryptography.
