> ## Documentation Index
> Fetch the complete documentation index at: https://docs.streambird.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Sign Message

The Sign Message screen is displayed when your application requests a wallet signature for an arbitrary message. This screen shows users the message content and allows them to approve or reject the signature request.

<Info>
  Message signing is commonly used for authentication, proving wallet ownership, or authorizing actions without sending a blockchain transaction.
</Info>

## How it works

When your application requests a message signature:

1. Your app calls the sign message method from the MoonKey SDK
2. The Sign Message screen appears, displaying the message content
3. User reviews the message details
4. User approves or rejects the signature request
5. If approved, the signed message is returned to your application

## Triggering the Sign Message screen

Use the `useSignMessage` hook from the MoonKey SDK to trigger the Sign Message screen:

<Tabs>
  <Tab title="Ethereum">
    ```tsx theme={null}
    import { useMoonKey } from '@moon-key/react-auth';
    import { useSignMessage } from '@moon-key/react-auth/ethereum';

    export default function SignMessageButton() {
      const { user } = useMoonKey();
      const { signMessage } = useSignMessage();
      
      const handleSign = async () => {
        if (!user?.wallet) {
          alert('No wallet found');
          return;
        }
        
        try {
          const result = await signMessage({
            message: 'Welcome to MyApp! Sign this message to prove you own this wallet.',
            wallet: user.wallet,
            options: {
              uiOptions: {
                title: 'Sign Message',
                description: 'Please sign this message to continue',
                buttonText: 'Sign',
                showWalletUI: true
              }
            }
          });
          console.log('Signature:', result.signature);
        } catch (error) {
          console.error('User rejected signature:', error);
        }
      };
      
      return <button onClick={handleSign}>Sign Message</button>;
    }
    ```
  </Tab>

  <Tab title="Solana">
    ```tsx theme={null}
    import { useMoonKey } from '@moon-key/react-auth';
    import { useSignMessage } from '@moon-key/react-auth/solana';

    export default function SignMessageButton() {
      const { user } = useMoonKey();
      const { signMessage } = useSignMessage();
      
      const handleSign = async () => {
        if (!user?.wallet) {
          alert('No wallet found');
          return;
        }
        
        try {
          // Convert string message to Uint8Array for Solana
          const messageBytes = new TextEncoder().encode(
            'Welcome to MyApp! Sign this message to prove you own this wallet.'
          );
          
          const result = await signMessage({
            message: messageBytes,
            wallet: user.wallet,
            options: {
              uiOptions: {
                title: 'Sign Message',
                description: 'Please sign this message to continue',
                buttonText: 'Sign',
                showWalletUI: true
              }
            }
          });
          console.log('Signature:', result.signature);
        } catch (error) {
          console.error('User rejected signature:', error);
        }
      };
      
      return <button onClick={handleSign}>Sign Message</button>;
    }
    ```
  </Tab>
</Tabs>

## Customizing the Sign Message screen

You can customize the Sign Message screen by passing UI options in the `options.uiOptions` object when calling `signMessage`:

```tsx theme={null}
const result = await signMessage({
  message: 'Your message content here',
  wallet: user.wallet,
  options: {
    uiOptions: {
      title: 'Verify Wallet Ownership',
      description: 'Sign this message to prove you control this wallet address',
      buttonText: 'Sign & Verify',
      showWalletUI: true
    }
  }
});
```

## Configuration options

### Basic UI Options

<ParamField path="title" type="string">
  Custom title text displayed at the top of the Sign Message screen.

  **Example:**

  ```tsx theme={null}
  options: {
    uiOptions: {
      title: 'Verify Your Identity'
    }
  }
  ```
</ParamField>

<ParamField path="description" type="string">
  Custom description text displayed below the title, providing context for the signature request.

  **Example:**

  ```tsx theme={null}
  options: {
    uiOptions: {
      description: 'Sign this message to prove you own this wallet and access your account'
    }
  }
  ```
</ParamField>

<ParamField path="buttonText" type="string">
  Custom text for the confirmation button.

  **Default:** `'Sign'`

  **Example:**

  ```tsx theme={null}
  options: {
    uiOptions: {
      buttonText: 'Approve & Sign'
    }
  }
  ```
</ParamField>

<ParamField path="showWalletUI" type="boolean">
  Whether to show wallet information (address, balance) in the Sign Message screen.

  **Default:** `true`

  **Example:**

  ```tsx theme={null}
  options: {
    uiOptions: {
      showWalletUI: false // Hide wallet details for a cleaner UI
    }
  }
  ```
</ParamField>

### Solana-specific Options

<ParamField path="commitment" type="TransactionCommitment">
  The commitment level to use for Solana transactions.

  **Available values:** `'processed'`, `'confirmed'`, `'finalized'`

  **Example:**

  ```tsx theme={null}
  options: {
    uiOptions: {
      commitment: 'confirmed'
    }
  }
  ```
</ParamField>

<ParamField path="encoding" type="TransactionEncoding">
  The encoding format for the Solana transaction.

  **Available values:** `'base58'`, `'base64'`

  **Example:**

  ```tsx theme={null}
  options: {
    uiOptions: {
      encoding: 'base64'
    }
  }
  ```
</ParamField>

## Common use cases

### Authentication verification

Prove wallet ownership for authentication:

```tsx theme={null}
import { useMoonKey } from '@moon-key/react-auth';
import { useSignMessage } from '@moon-key/react-auth/ethereum';

export default function VerifyWallet() {
  const { user } = useMoonKey();
  const { signMessage } = useSignMessage();
  
  const verifyOwnership = async () => {
    if (!user?.wallet) return;
    
    try {
      const result = await signMessage({
        message: `Sign this message to verify you own this wallet.\n\nTimestamp: ${Date.now()}`,
        wallet: user.wallet,
        options: {
          uiOptions: {
            title: 'Verify Wallet Ownership',
            description: 'Please sign to confirm you control this wallet',
            buttonText: 'Verify',
            showWalletUI: true
          }
        }
      });
      
      // Send signature to your backend for verification
      await fetch('/api/verify-wallet', {
        method: 'POST',
        body: JSON.stringify({ signature: result.signature })
      });
      
      alert('Wallet verified successfully!');
    } catch (error) {
      console.error('Verification failed:', error);
    }
  };
  
  return <button onClick={verifyOwnership}>Verify Wallet</button>;
}
```

### Third-party service login

Sign in to external services with wallet signature:

```tsx theme={null}
const loginToThirdParty = async () => {
  if (!user?.wallet) return;
  
  const nonce = await fetchNonceFromService();
  
  const result = await signMessage({
    message: `Sign in to ThirdPartyApp\n\nNonce: ${nonce}`,
    wallet: user.wallet,
    options: {
      uiOptions: {
        title: 'Sign In to ThirdPartyApp',
        description: 'Authorize connection to ThirdPartyApp with your wallet',
        buttonText: 'Sign In',
        showWalletUI: true
      }
    }
  });
  
  // Send signature to third-party service
  await authenticateWithService(result.signature);
};
```

### Action authorization

Authorize specific actions without gas fees:

```tsx theme={null}
const authorizeAction = async (actionType: string, details: string) => {
  if (!user?.wallet) return;
  
  const result = await signMessage({
    message: `Authorize Action: ${actionType}\n\nDetails: ${details}\n\nTimestamp: ${Date.now()}`,
    wallet: user.wallet,
    options: {
      uiOptions: {
        title: `Authorize ${actionType}`,
        description: 'Sign this message to authorize the action',
        buttonText: 'Authorize',
        showWalletUI: false
      }
    }
  });
  
  return result.signature;
};
```

### Terms and conditions acceptance

Cryptographically sign terms acceptance:

```tsx theme={null}
const acceptTerms = async () => {
  if (!user?.wallet) return;
  
  const result = await signMessage({
    message: `I accept the Terms of Service and Privacy Policy of MyApp.\n\nVersion: 2.0\nDate: ${new Date().toISOString()}`,
    wallet: user.wallet,
    options: {
      uiOptions: {
        title: 'Accept Terms of Service',
        description: 'Sign to acknowledge that you have read and agree to our terms',
        buttonText: 'I Accept',
        showWalletUI: false
      }
    }
  });
  
  // Store signature as proof of acceptance
  await storeTermsAcceptance(result.signature);
};
```

## Complete example

Here's a complete example with custom UI configuration:

```tsx theme={null}
'use client';
import { useMoonKey } from '@moon-key/react-auth';
import { useSignMessage } from '@moon-key/react-auth/ethereum';
import { useState } from 'react';

export default function SignMessageDemo() {
  const { user, isAuthenticated } = useMoonKey();
  const { signMessage } = useSignMessage();
  const [signature, setSignature] = useState<string | null>(null);
  
  if (!isAuthenticated) {
    return <div>Please sign in first</div>;
  }
  
  if (!user?.wallet) {
    return <div>No wallet found</div>;
  }
  
  const handleSignMessage = async () => {
    try {
      const result = await signMessage({
        message: `Welcome to MyApp!\n\nWallet: ${user.wallet.address}\nTimestamp: ${Date.now()}\n\nSign this message to verify your identity.`,
        wallet: user.wallet,
        options: {
          uiOptions: {
            title: 'Verify Your Identity',
            description: 'Sign this message to prove you control this wallet',
            buttonText: 'Sign & Verify',
            showWalletUI: true
          }
        }
      });
      
      setSignature(result.signature);
      console.log('Message signed successfully:', result.signature);
    } catch (error) {
      console.error('Failed to sign message:', error);
      alert('Signature rejected or failed');
    }
  };
  
  return (
    <div>
      <h2>Sign Message Example</h2>
      <p>Wallet: {user.wallet.address}</p>
      
      <button onClick={handleSignMessage}>
        Sign Message
      </button>
      
      {signature && (
        <div style={{ marginTop: '20px' }}>
          <h3>Signature:</h3>
          <pre style={{ 
            background: '#f5f5f5', 
            padding: '10px', 
            borderRadius: '5px',
            overflow: 'auto'
          }}>
            {signature}
          </pre>
        </div>
      )}
    </div>
  );
}
```

## User experience flow

<Steps>
  <Step title="Trigger signature request">
    Your application calls `signMessage()` with a message, wallet, and optional UI options.
  </Step>

  <Step title="Sign Message screen appears">
    The customized Sign Message screen is displayed to the user.
  </Step>

  <Step title="Review message">
    User reviews the message content, title, and description.
  </Step>

  <Step title="Approve or reject">
    User clicks the confirm button to sign, or cancels/closes the modal to reject.
  </Step>

  <Step title="Signature created">
    If approved, MoonKey signs the message with the user's wallet private key.
  </Step>

  <Step title="Return to application">
    The signature is returned to your application as an object containing the signature string (Ethereum) or Uint8Array (Solana).
  </Step>
</Steps>

## Message signing vs. transaction signing

It's important to understand the difference:

<AccordionGroup>
  <Accordion title="Message Signing (this screen)">
    * Signs arbitrary text or data
    * **Does not** cost gas fees
    * **Does not** modify blockchain state
    * Used for authentication, verification, or authorization
    * Instant and free
    * Example: "Sign this message to log in"
  </Accordion>

  <Accordion title="Transaction Signing">
    * Signs blockchain transactions
    * **Costs gas fees** (requires native currency)
    * **Modifies** blockchain state (transfers tokens, calls contracts, etc.)
    * Used for actual blockchain operations
    * Requires network confirmation
    * Example: "Sign this transaction to send 1 ETH"
  </Accordion>
</AccordionGroup>

## Best practices

<AccordionGroup>
  <Accordion title="Provide clear context">
    Always include a clear `description` explaining why the user needs to sign:

    ```tsx theme={null}
    options: {
      uiOptions: {
        title: 'Verify Wallet',
        description: 'Sign this message to prove you own this wallet. This will not cost any gas.'
      }
    }
    ```
  </Accordion>

  <Accordion title="Include timestamps or nonces">
    Prevent replay attacks by including unique data:

    ```tsx theme={null}
    message: `Action: Login\nTimestamp: ${Date.now()}\nNonce: ${randomNonce}`
    ```
  </Accordion>

  <Accordion title="Use descriptive button text">
    Make it clear what the user is signing:

    ```tsx theme={null}
    options: {
      uiOptions: {
        buttonText: 'Sign & Verify' // Better than just "Sign"
      }
    }
    ```
  </Accordion>

  <Accordion title="Handle rejections gracefully">
    Users may decline to sign. Always handle errors:

    ```tsx theme={null}
    try {
      const result = await signMessage({ 
        message: '...', 
        wallet: user.wallet 
      });
      console.log('Signature:', result.signature);
    } catch (error) {
      // User rejected - show friendly message
      toast.error('Signature required to continue');
    }
    ```
  </Accordion>

  <Accordion title="Show wallet details when relevant">
    Use `showWalletUI: true` when wallet context is important:

    ```tsx theme={null}
    options: {
      uiOptions: {
        showWalletUI: true // Show address and balance
      }
    }
    ```

    Set to `false` for a cleaner UI when wallet details aren't relevant.
  </Accordion>

  <Accordion title="Keep messages concise">
    Users are more likely to read and understand shorter messages:

    * Use clear, simple language
    * Break long messages into lines with `\n`
    * Highlight important information
  </Accordion>

  <Accordion title="Check for wallet before signing">
    Always verify the user has a wallet before attempting to sign:

    ```tsx theme={null}
    if (!user?.wallet) {
      alert('Please create a wallet first');
      return;
    }
    ```
  </Accordion>
</AccordionGroup>

## Global appearance settings

The Sign Message screen also respects global appearance settings from `MoonKeyProvider`:

```tsx theme={null}
<MoonKeyProvider
  publishableKey="your_publishable_key"
  config={{
    appearance: {
      logo: 'https://myapp.com/logo.png', // Displayed on all UI components
      hideClose: false // Allow users to cancel signing
    }
  }}
>
  {children}
</MoonKeyProvider>
```

Learn more about [configuring appearance](/get-started/frontend-sdks/react/advance/configure-appearance).

## Security considerations

<Warning>
  Never sign messages without reviewing their content. Malicious applications could trick users into signing messages that authorize unwanted actions.
</Warning>

**For developers:**

1. **Verify signatures server-side** - Always validate signatures on your backend before trusting them
2. **Use nonces** - Include unique identifiers to prevent replay attacks
3. **Include context** - Clearly state what the signature authorizes
4. **Set expiration** - Include timestamps and reject old signatures
5. **Validate message format** - Ensure the signed message matches your expected format

**For users:**

The Sign Message screen helps users by:

* Displaying the full message content
* Showing their wallet address
* Providing clear context via title and description
* Allowing them to reject the request

## Verifying signatures

After obtaining a signature, you typically want to verify it on your backend:

<Tabs>
  <Tab title="Ethereum">
    ```typescript theme={null}
    import { verifyMessage } from 'viem';

    // On your frontend, after signing
    const result = await signMessage({
      message: 'Your message',
      wallet: user.wallet
    });

    // Send result.signature to your backend
    const response = await fetch('/api/verify', {
      method: 'POST',
      body: JSON.stringify({
        message: 'Your message',
        signature: result.signature,
        address: user.wallet.address
      })
    });

    // On your backend
    const isValid = await verifyMessage({
      address: userWalletAddress,
      message: originalMessage,
      signature: receivedSignature
    });

    if (isValid) {
      // Signature is valid - user owns the wallet
      console.log('Signature verified!');
    }
    ```
  </Tab>

  <Tab title="Solana">
    ```typescript theme={null}
    import { PublicKey } from '@solana/web3.js';
    import nacl from 'tweetnacl';

    // On your frontend, after signing
    const result = await signMessage({
      message: messageBytes,
      wallet: user.wallet
    });

    // Convert Uint8Array to base64 for transmission
    const signatureBase64 = Buffer.from(result.signature).toString('base64');

    // Send to your backend
    const response = await fetch('/api/verify', {
      method: 'POST',
      body: JSON.stringify({
        message: Buffer.from(messageBytes).toString('base64'),
        signature: signatureBase64,
        address: user.wallet.address
      })
    });

    // On your backend
    const publicKey = new PublicKey(userWalletAddress);
    const messageBytes = Buffer.from(receivedMessage, 'base64');
    const signatureBytes = Buffer.from(receivedSignature, 'base64');

    const isValid = nacl.sign.detached.verify(
      messageBytes,
      signatureBytes,
      publicKey.toBytes()
    );

    if (isValid) {
      console.log('Signature verified!');
    }
    ```
  </Tab>
</Tabs>

## Next steps

<CardGroup cols={2}>
  <Card title="Sign Transaction" icon="file-signature" href="/authentication/user-authentication/ui-components/sign-transaction">
    Sign blockchain transactions
  </Card>

  <Card title="Send Transaction" icon="paper-plane" href="/authentication/user-authentication/ui-components/send-transaction">
    Send transactions with UI
  </Card>

  <Card title="UI Components Overview" icon="window-maximize" href="/authentication/user-authentication/ui-components/overview">
    Explore all UI components
  </Card>

  <Card title="Configure Appearance" icon="palette" href="/get-started/frontend-sdks/react/advance/configure-appearance">
    Global appearance settings
  </Card>
</CardGroup>
