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

# Sign a message

<Info>
  This method uses Ethereum's `personal_sign` RPC method. If you are looking for a low-level raw
  signature over a input hash, see
  [secp256k1\_sign](/wallets/using-wallets/ethereum/sign-a-raw-hash).
</Info>

<Info>
  When using Privy's server-side SDKs to sign messages, you can use the authorization context to
  automatically sign requests. Learn more about [signing on the
  server](/controls/authorization-keys/using-owners/sign/signing-on-the-server).
</Info>

<View title="React" icon="react">
  Use the `signMessage` method exported from the `useSignMessage` hook to sign a message with an Ethereum embedded wallet.

  ### Usage

  ```tsx theme={"system"}
  import {useSignMessage, useWallets} from '@privy-io/react-auth';

  const {signMessage} = useSignMessage();
  const {wallets} = useWallets();

  const uiOptions = {
    title: 'You are voting for foobar project'
  };

  const {signature} = await signMessage(
    {message: 'I hereby vote for foobar'},
    {
      uiOptions,
      address: wallets[0].address // Optional: Specify the wallet to use for signing. If not provided, the first wallet will be used.
    }
  );
  ```

  ### Parameters

  <ParamField path="message" type="string" required>
    Message to be signed.
  </ParamField>

  <ParamField path="options" type="Object">
    <Expandable title="properties" defaultOpen="true">
      <ParamField path="uiOptions" type="SignMessageModalUIOptions">
        UI options to customize the signature prompt modal. [Learn
        more](/wallets/using-wallets/ui-components)

        <Tip>
          To hide confirmation modals, set `options.uiOptions.showWalletUIs` to `false`. Learn more
          about configuring modal prompts [here](/recipes/react/manage-wallet-UIs).
        </Tip>
      </ParamField>

      <ParamField path="address" type="string">
        Address of the wallet to use for signing the message. **Recommended when working with external
        wallets** to ensure reliable functionality. If not provided, the first wallet will be used.
      </ParamField>
    </Expandable>
  </ParamField>

  ### Returns

  {' '}

  <ResponseField name="signature" type="string">
    The signature produced by the wallet.
  </ResponseField>

  ### Callbacks

  Configure callbacks for Privy's `signMessage` method on the `useSignMessage` hook:

  ```tsx theme={"system"}
  import {useSignMessage} from '@privy-io/react-auth';

  const {signMessage} = useSignMessage({
    onSuccess: ({signature}) => {
      console.log(signature);
      // Any logic you'd like to execute after a user successfully signs a message
    },
    onError: (error) => {
      console.log(error);
      // Any logic you'd like to execute after a user exits the message signing flow or there is an error
    }
  });

  // Then call `signMessage` in your code, which will invoke these callbacks on completion
  ```

  As parameters to **`useSignMessage`**, you may include an **`onSuccess`** callback and/or an **`onError`** callback.

  While this component is mounted, any invocation of **`signMessage`** will trigger the **`onSuccess`** callback or **`onError`** callback on completion, depending on if the message was successfully signed or not.

  #### onSuccess

  If set, the **`onSuccess`** callback will execute after a user has successfully signed the message. Within this callback, you can access a **`signature`** parameter, which is the **`signature`** string value generated by the wallet to sign the message.

  #### onError

  If set, the **`onError`** callback will execute after a user attempts to sign a message and there is an error, or if the user exits the signature flow prematurely. Within this callback, you may access an **`error`** code with more information about the error.
</View>

<View title="React Native" icon="react">
  Request a message signature on the wallets Ethereum provider.

  ### Usage

  ```tsx theme={"system"}
  import {useEmbeddedEthereumWallet} from '@privy-io/expo';

  const {wallets} = useEmbeddedEthereumWallet();
  const wallet = wallets[0];

  // Get an EIP-1193 Provider
  const provider = await wallet.getProvider();
  // Get address
  const accounts = await provider.request({
    method: 'eth_requestAccounts'
  });

  // Sign message
  const message = 'I hereby vote for foobar';
  const signature = await provider.request({
    method: 'personal_sign',
    params: [message, accounts[0]]
  });
  ```

  ### Parameters

  <ParamField path="method" type="'personal_sign'" required>
    The method for the wallet request. For signing messages, this is `'personal_sign'`.
  </ParamField>

  <ParamField path="params" type="Object" required>
    <Expandable title="properties" defaultOpen="true">
      <ParamField path="message" type="string | Uint8Array" required>
        The string or bytes to sign with the wallet.
      </ParamField>

      <ParamField path="address" type="string">
        The address of the wallet to sign the message with.
      </ParamField>
    </Expandable>
  </ParamField>

  ### Returns

  <ResponseField name="signature" type="string">
    The signature produced by the wallet.
  </ResponseField>
</View>

<View title="Swift" icon="swift">
  Request a message signature on the wallet's Ethereum provider.

  ### Usage

  ```swift theme={"system"}
  guard let user = privy.user else {
      // If user is null, user is not authenticated
      return
  }

  // Retrieve list of user's embedded Ethereum wallets
  let ethereumWallets = user.embeddedEthereumWallets

  // Grab the desired wallet. Here, we retrieve the first wallet
  guard let wallet = ethereumWallets.first else {
      // No ETH wallets
      return
  }

  let signature = try await wallet.provider.request(.personalSign(message: "A message to sign", address: wallet.add))

  print("Result signature: \(signature)")
  ```

  ### Parameters

  <ParamField path="message" type="string" required>
    The string to sign with the wallet.
  </ParamField>

  <ParamField path="address" type="string">
    The address of the wallet to sign the message with.
  </ParamField>

  ### Returns

  <ResponseField name="signature" type="string">
    The signature produced by the wallet.
  </ResponseField>
</View>

<View title="Android" icon="android">
  ### Usage

  ```kotlin theme={"system"}
  // Get Privy user
  val user = privy.user

  // check if user is authenticated
  if (user != null) {
    // Retrieve list of user's embedded Ethereum wallets
    val ethereumWallets = user.embeddedEthereumWallets

    if (ethereumWallets.isNotEmpty()) {
      // Grab the desired wallet. Here, we retrieve the first wallet
      val ethereumWallet = ethereumWallets.first()

      // Make an rpc request
      ethereumWallet.provider.request(
        request = EthereumRpcRequest.personalSign("A message to sign", ethereumWallet.address),
      )
    }
  }
  ```

  ### Parameters

  <ParamField path="method" type="'personal_sign'" required>
    The method for the wallet request. For signing messages, this is `'personal_sign'`.
  </ParamField>

  <ParamField path="params" type="Object" required>
    <Expandable title="properties" defaultOpen="true">
      <ParamField path="message" type="string | Uint8Array" required>
        The string or bytes to sign with the wallet.
      </ParamField>

      <ParamField path="address" type="string">
        The address of the wallet to sign the message with.
      </ParamField>
    </Expandable>
  </ParamField>

  ### Returns

  {' '}

  <ResponseField name="signature" type="string">
    The signature produced by the wallet.
  </ResponseField>
</View>

<View title="Unity" icon="unity">
  ### Usage

  ```csharp theme={"system"}
  try {
      IPrivyUser privyUser = await PrivyManager.Instance.GetUser();
      IEmbeddedEthereumWallet embeddedWallet = privyUser.EmbeddedEthereumWallets[0];
      var rpcRequest = new RpcRequest
      {
          Method = "personal_sign",
          Params = new string[] { "A message to sign", embeddedWallet.Address }
      };
      RpcResponse personalSignResponse = await embeddedWallet.RpcProvider.Request(rpcRequest);
      Debug.Log(personalSignResponse.Data);
  } catch (PrivyWalletException ex){
      Debug.LogError($"Could not sign message due to error: {ex.Error} {ex.Message}");
  } catch (Exception ex) {
      Debug.LogError($"Could not sign message exception {ex.Message}");
  }
  ```

  ### Parameters

  <ParamField path="method" type="'personal_sign'" required>
    The method for the wallet request. For signing messages, this is `'personal_sign'`.
  </ParamField>

  <ParamField path="params" type="Object" required>
    <Expandable title="properties" defaultOpen="true">
      <ParamField path="message" type="string | Uint8Array" required>
        The string or bytes to sign with the wallet.
      </ParamField>

      <ParamField path="address" type="string">
        The address of the wallet to sign the message with.
      </ParamField>
    </Expandable>
  </ParamField>

  ### Returns

  {' '}

  <ResponseField name="signature" type="string">
    The signature produced by the wallet.
  </ResponseField>
</View>

<View title="Flutter" icon="flutter">
  ### Usage

  ```dart theme={"system"}
  // Get an EIP-1193 Provider
  final ethereumWallet = privy.user.embeddedEthereumWallets.first;
  final provider = ethereumWallet.provider;

  // Sign message
  final message = 'A message to you Rudy';
  final request = EthereumRpcRequest(
    method: 'personal_sign',
    params: [message, ethereumWallet.address],
  );

  final result = await provider.request(request);

  result.fold(
    onSuccess: (response) {
      final signature = response.data;
      print('Signature: $signature');
    },
    onFailure: (error) {
      print('Error signing message: ${error.message}');
    },
  );
  ```

  ### Parameters

  <ParamField path="method" type="'personal_sign'" required>
    The method for the wallet request. For signing messages, this is `'personal_sign'`.
  </ParamField>

  <ParamField path="params" type="Object" required>
    <Expandable title="properties" defaultOpen="true">
      <ParamField path="message" type="string | Uint8Array" required>
        The string or bytes to sign with the wallet.
      </ParamField>

      <ParamField path="address" type="string">
        The address of the wallet to sign the message with.
      </ParamField>
    </Expandable>
  </ParamField>

  ### Returns

  <ResponseField name="method" type="'personal_sign'">
    The RPC method executed with the wallet.
  </ResponseField>

  <ResponseField name="data" type="Object">
    Outputs for the RPC method executed with the wallet.

    <Expandable title="properties" defaultOpen="true">
      <ResponseField name="signature" type="string">
        An encoded string serializing the signature produced by the user's wallet.
      </ResponseField>
    </Expandable>
  </ResponseField>
</View>

<View title="NodeJS" icon="node-js">
  Use the `signMessage` method on the Ethereum interface to sign a message with an Ethereum wallet.

  ### Usage

  ```tsx theme={"system"}
  const {signature, encoding} = await privy.wallets().ethereum().signMessage('insert-wallet-id', {
    message: 'Hello world'
  });
  ```

  ### Parameters and Returns

  Check out the [API reference](/api-reference/wallets/ethereum/personal-sign) for more details.
</View>

<View title="Java" icon="java">
  To sign a message from your wallet, use the `signMessage` method.
  It will sign your message, and return the signature to you.

  ### Usage

  ```java theme={"system"}
  try {
      String message = "Hello, Ethereum.";

      // Example: If wallet's owner is an authorization private key
      AuthorizationContext authorizationContext = AuthorizationContext.builder()
          .addAuthorizationPrivateKey("authorization-key")
          .build();

      EthereumPersonalSignRpcResponseData response = privyClient
          .wallets()
          .ethereum()
          .signMessage(
              walletId,
              message.getBytes(StandardCharsets.UTF_8),
              authorizationContext
          );

      String signature = response.signature();
  } catch (APIException e) {
      String errorBody = e.bodyAsString();
      System.err.println(errorBody);
  } catch (Exception e) {
      System.err.println(e.getMessage());
  }
  ```

  ### Parameters

  When signing a message with your Ethereum wallet, you can sign over the raw bytes of the message or a hex string encoding.

  <ParamField type="byte[]" body="message">
    The raw bytes of the message to sign over.
  </ParamField>

  <ParamField type="String" body="message">
    Alternatively, a hex string encoding of the message to sign over.
  </ParamField>

  ### Returns

  The `EthereumPersonalSignRpcResponseData` object contains a `signature()` field

  <ResponseField name="signature()" type="String">
    The signature produced by the wallet.
  </ResponseField>
</View>

<View title="Rust" icon="rust">
  Use the `sign_message` method on the Ethereum service to sign a UTF-8 message with an Ethereum wallet.

  ### Usage

  ```rust theme={"system"}
  use privy_rs::{AuthorizationContext, PrivyClient};

  let client = PrivyClient::new("app_id".to_string(), "app_secret".to_string())?;
  let ethereum_service = client.wallets().ethereum();
  let auth_ctx = AuthorizationContext::new();

  let signature = ethereum_service
      .sign_message(
          &wallet_id,
          "Hello, Ethereum!",
          &auth_ctx,
          Some("unique-request-id-123"),
      )
      .await?;

  println!("Message signed successfully");
  ```

  ### Parameters and Returns

  See the Rust SDK documentation for detailed parameter and return types, including embedded examples:

  * [EthereumService::sign\_message](https://docs.rs/privy-rs/latest/privy_rs/ethereum/struct.EthereumService.html#method.sign_message)

  For REST API details, see the [API reference](/api-reference/wallets/ethereum/personal-sign).
</View>

<View title="Go" icon="golang">
  Use the `SignMessage` method on the Ethereum service to sign a message with an Ethereum wallet.

  ### Usage

  ```go theme={"system"}
  response, err := client.Wallets.Ethereum.SignMessage(
      context.Background(),
      "wallet-id",
      "Hello, Ethereum!",
  )
  if err != nil {
      log.Fatalf("failed to sign message: %v", err)
  }

  fmt.Println("Signature:", response.Signature)
  ```

  ### Parameters and Returns

  See the [API reference](/api-reference/wallets/ethereum/personal-sign) for more details.
</View>

<View title="Ruby" icon="gem">
  Use the `rpc` method on the `wallets` service with the `personal_sign` method to sign a message with an Ethereum wallet.

  ### Usage

  ```ruby theme={"system"}
  response = client.wallets.rpc(
    "wallet-id",
    wallet_rpc_request_body: {
      method: "personal_sign",
      chain_type: "ethereum",
      params: {message: "Hello, Ethereum!", encoding: "utf-8"}
    },
    authorization_context: ctx
  )

  puts(response.data.signature)
  ```

  ### Parameters and Returns

  See the [API reference](/api-reference/wallets/ethereum/personal-sign) for more details.
</View>

<View title="REST API" icon="terminal">
  To sign a message make a POST request to

  ```bash theme={"system"}
  https://api.privy.io/v1/wallets/<wallet_id>/rpc
  ```

  ### Parameters

  <ParamField path="method" type="'personal_sign'" required>
    RPC method to execute with the wallet.
  </ParamField>

  <ParamField path="params" type="Object" required>
    Parameters for the RPC method to execute with the wallet.

    <Expandable title="properties" defaultOpen="true">
      <ParamField path="message" type="string" required>
        The message to sign with the wallet. If the message to sign is raw bytes, you must serialize
        the message as a hexadecimal string.
      </ParamField>

      <ParamField path="encoding" type="'utf-8' | 'hex'" required>
        The encoding format for `params.message`. Use `utf-8` for a string message and `hex` for
        bytes.
      </ParamField>
    </Expandable>
  </ParamField>

  ### Returns

  <ResponseField name="method" type="'personal_sign'">
    The RPC method executed with the wallet.
  </ResponseField>

  <ResponseField name="data" type="Object">
    Outputs for the RPC method executed with the wallet.

    <Expandable title="properties" defaultOpen="true">
      <ResponseField name="signature" type="string">
        An encoded string serializing the signature produced by the user's wallet.
      </ResponseField>

      <ResponseField name="encoding" type="'hex'">
        The encoding format for the returned `signature`. Currently, only `'hex'` is supported for Ethereum.
      </ResponseField>
    </Expandable>
  </ResponseField>

  ### Usage

  ```bash theme={"system"}
  $ curl --request POST https://api.privy.io/v1/wallets/<wallet_id>/rpc \
  -u "<your-privy-app-id>:<your-privy-app-secret>" \
  -H "privy-app-id: <your-privy-app-id>" \
  -H "privy-authorization-signature: <authorization-signature-for-request>" \
  -H 'Content-Type: application/json' \
  -d '{
    "chain_type": "ethereum",
    "method": "personal_sign",
    "params": {
      "message": "Hello, Ethereum.",
      "encoding": "utf-8"
    }
  }'
  ```
</View>

<Info>
  Looking to send USDC or another ERC-20 token? See our [Send USDC](/recipes/send-usdc) recipe.
</Info>
