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

# Personal Signatures

## Overview

Magic offers out-of-the-box Signature Request UI when the user is prompted to sign a personal or typed message for the following EVM RPC methods:

* `personal_sign`
* `eth_signTypedData_v3`
* `eth_signTypedData_v4`

These methods allow dApps to verifiably prove the ownership of the user's account by getting a signature from their private key and using it to sign arbitrary and/or typed data. Additionally, it is possible to obtain a user's signature during login in a single step using [login with verification feature](/embedded-wallets/authentication/customization/login-ui#usage-0).

<Frame>
  <img src="https://mintcdn.com/magic-newton/1GYf0YW8BthDpWqo/images/Personal-Signature.webp?fit=max&auto=format&n=1GYf0YW8BthDpWqo&q=85&s=31d1bd065e5982c2dbb163635195753d" alt="Personal-Signature" width="800" height="600" data-path="images/Personal-Signature.webp" />
</Frame>

#### Compatibility

* Personal Signature UI is disabled by default and can be enabled within the developer dashboard in Customization -> Widget UI. Magic also offers [Sign Confirmation](/embedded-wallets/wallets/security/sign-confirmation), a feature that secures users from front-end attacks, by prompting them to confirm the transaction in a Magic-hosted tab after clicking "Send".

### Use Cases

* Prove verifiable ownership of a public address through signing arbitrary data provided by the dApp
* Used in various scenarios where a user needs to sign a structured message as proof of their approval

### Usage

⁠Once you have verified the correct setup of the Magic SDK and successfully authenticated the user, you can request consent to collect their information:

<Tabs>
  <Tab title="personal_sign">
    ```javascript JavaScript icon="square-js" theme={null}

    import { BrowserProvider } from "ethers";
    import { Magic } from "magic-sdk";
    import { recoverPersonalSignature } from "@metamask/eth-sig-util";

    const magic = new Magic("YOUR_API_KEY", {
      network: "sepolia",
    });
    const provider = new BrowserProvider(magic.rpcProvider);

    const signAndVerify = async () => {
      const signer = await provider.getSigner();
      const account = await signer.getAddress();
      const message = "Here is a basic message!";
      const signedMessage = await magic.rpcProvider.request({
        method: "personal_sign",
        params: [message, account],
      });
      console.log("signedMessage:", signedMessage);
      // recover the public address of the signer to verify
      const recoveredAddress = recoverPersonalSignature({
        data: message,
        signature: signedMessage,
      });
      console.log(
        recoveredAddress.toLocaleLowerCase() === account.toLocaleLowerCase()
          ? "Signing success!"
          : "Signing failed!"
      );
    };
    ```
  </Tab>

  <Tab title="signTypedData_v3">
    ```javascript JavaScript icon="square-js" theme={null}
    import { BrowserProvider } from "ethers";
    import { Magic } from "magic-sdk";
    import { recoverTypedSignature } from "@metamask/eth-sig-util";

    const magic = new Magic("YOUR_API_KEY", {
      network: "sepolia",
    });
    const provider = new BrowserProvider(magic.rpcProvider);

    export const signTypedDataV3Payload = {
      types: {
        EIP712Domain: [
          {
            name: "name",
            type: "string",
          },
          {
            name: "version",
            type: "string",
          },
          {
            name: "verifyingContract",
            type: "address",
          },
        ],
        Greeting: [
          {
            name: "contents",
            type: "string",
          },
        ],
      },
      primaryType: "Greeting",
      domain: {
        name: "Magic",
        version: "1",
        verifyingContract: "0xE0cef4417a772512E6C95cEf366403839b0D6D6D",
      },
      message: {
        contents: "Hello, from Magic!",
      },
    };

    const signAndVerify = async () => {
      const signer = await provider.getSigner();
      const account = await signer.getAddress();
      const params = [account, signTypedDataV3Payload];
      const method = "eth_signTypedData_v3";
      const signature = await magic.rpcProvider.request({
        method,
        params,
      });
      console.log("signature:", signature);
      // recover the public address of the signer to verify
      const recoveredAddress = recoverTypedSignature({
        data: signTypedDataV3Payload,
        signature,
        version: "V3",
      });

      console.log(
        recoveredAddress.toLocaleLowerCase() === account.toLocaleLowerCase()
          ? "Signing success!"
          : "Signing failed!"
      );
    };
    ```
  </Tab>

  <Tab title="signTypedData_v4">
    ```javascript JavaScript icon="square-js" theme={null}
    import { BrowserProvider } from "ethers";
    import { Magic } from "magic-sdk";
    import { recoverTypedSignature } from "@metamask/eth-sig-util";

    const magic = new Magic("YOUR_API_KEY", {
      network: "sepolia",
    });
    const provider = new BrowserProvider(magic.rpcProvider);

    export const signTypedDataV4Payload = {
      domain: {
        chainId: 11155111,
        name: "Ether Mail",
        verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
        version: "1",
      },
      message: {
        contents: "Hello, Bob!",
        from: {
          name: "Cow",
          wallets: [
            "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
            "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF",
          ],
        },
        to: [
          {
            name: "Bob",
            wallets: [
              "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
              "0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57",
              "0xB0B0b0b0b0b0B000000000000000000000000000",
            ],
          },
        ],
      },
      primaryType: "Mail",
      types: {
        EIP712Domain: [
          { name: "name", type: "string" },
          { name: "version", type: "string" },
          { name: "chainId", type: "uint256" },
          { name: "verifyingContract", type: "address" },
        ],
        Group: [
          { name: "name", type: "string" },
          { name: "members", type: "Person[]" },
        ],
        Mail: [
          { name: "from", type: "Person" },
          { name: "to", type: "Person[]" },
          { name: "contents", type: "string" },
        ],
        Person: [
          { name: "name", type: "string" },
          { name: "wallets", type: "address[]" },
        ],
      },
    };

    const signAndVerify = async () => {
      const signer = await provider.getSigner();
      const account = await signer.getAddress();
      const params = [account, signTypedDataV4Payload];
      const method = "eth_signTypedData_v4";
      const signature = await magic.rpcProvider.request({
        method,
        params,
      });
      console.log("signature:", signature);
      // recover the public address of the signer to verify
      const recoveredAddress = recoverTypedSignature({
        data: signTypedDataV4Payload,
        signature,
        version: "V4",
      });

      console.log(
        recoveredAddress.toLocaleLowerCase() === account.toLocaleLowerCase()
          ? "Signing success!"
          : "Signing failed!"
      );
    };
    ```
  </Tab>
</Tabs>

### Configuration

See how to brand this experience with your own logo and colors in the [customization section](/embedded-wallets/wallets/customization/brand-and-theme). ⁠

### Resources

* [Quickstart](/embedded-wallets/quickstart/overview)
* [Supported EVM RPC Methods](/embedded-wallets/sdk/client-side/javascript#evm-rpc-methods)
