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

# URL signing

> Protecting your sensitive data

MoonPay is highly committed to security. For this reason, whenever sensitive information such as emails or wallet addresses are transmitted to the widget, you are required to use the `signature` parameter, otherwise the MoonPay widget fails to load. This measure makes it more difficult for unauthorized third parties to misuse the widget's pre-fill feature.

A signed URL helps limit access from unauthorized third parties by providing limited permissions and time to make a request. Passing the `signature` parameter is mandatory if you're using the `walletAddress` or `walletAddresses` parameter and it must be appended at the end of the URL. If your widget URL contains sensitive information, use the `signature` parameter.

You can generate a `signature` of the URL server-side and append it to the end of the URL. If the `signature` is provided, we'll check the validity of the query string to make sure it has not been altered. If the signature is invalid for any reason the MoonPay widget will fail to load.

## How to sign URLs

Follow these steps for signing URLs:

1. Send your widget URL to your backend server.
2. Generate the signature using the secret key found in your [MoonPay dashboard](https://dashboard.moonpay.com/developers/).
   * Use your own code to generate signatures and sign URLs
   * Alternatively, use [our Node SDK](/widget/on-ramp/integration-methods/sdks/node) to generate signatures, sign URLs, and validate signatures.
3. Return either the signature or entire signed URL.
   * **If using a SDK**, return the signature and use `updateSignature`. Do not encode the signature, as the SDK handles this.
   * **If using a URL-based integration**, return the entire signed URL. Make sure the value of `signature` and other parameters are URL-encoded.
4. Show the widget using the SDK or URL.

<Info>
  **Returning the signature vs entire signed URL**

  **Integrations using an SDK**: Return the signature by itself and use `updateSignature`

  **Integrations using URLs**: Return the entire signed URL
</Info>

## How to generate signatures

1. Create an HMAC (Hash-Based Message Authentication Code) using the SHA-256 hash function.
   1. Use your secret API key as the key and the original URL's query string as the message.
2. For URL-based integrations, make sure all query parameter values are URL-encoded before creating the signature.

<Info>
  All query parameter *values* (not the entire query string) need to be
  URL-encoded before generating the signature for it to be valid.
</Info>

## Code examples

### Integrations using an SDK

Integrations using a web or mobile SDK should calculate the signature, then return the signature by itself, not URL-encoded.

More details about signing with each SDK:

* [Web SDK](/widget/on-ramp/integration-methods/sdks/web#signing)
* [React SDK](/widget/on-ramp/integration-methods/sdks/react#url-signing)
* [React Native SDK](/widget/on-ramp/integration-methods/sdks/react-native#initialize)

<CodeGroup>
  ```typescript Node.js theme={null}
  import crypto from 'crypto';

  const secretKey = 'sk_test_key'; // Use your secret key

  const generateSignature = (url) => {
  const signature = crypto
  .createHmac('sha256', secretKey)
  .update(new URL(url).search) // Use the query string part of the URL
  .digest('base64'); // Convert the result to a base64 string

      console.log(signature) // Print the signature
      return signature // Return the signature

  };
  ```

  ```php PHP theme={null}
  <?php
    $host = 'https://buy-sandbox.moonpay.com';  // Base URL
    $query = '?apiKey=pk_test_key&currencyCode=eth&walletAddress=0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae';  // Query parameters

    $secretKey = 'sk_test_key';  // Your secret key

    // Create the HMAC SHA-256 hash and encode it in base64
    $signature = base64_encode(hash_hmac('sha256', $query, $secretKey, true));

    echo $signature;  // Print the signature
  ?>
  ```
</CodeGroup>

### Integrations using URLs

Integrations generating widget URLs should calculate the signature, URL-encode the signature, then return the whole signed URL.

<CodeGroup>
  ```typescript Node.js theme={null}
  import crypto from 'crypto';

  const originalUrl = '<https://buy-sandbox.moonpay.com?apiKey=pk_test_key&currencyCode=eth&walletAddress=0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae>';

  const signature = crypto
  .createHmac('sha256', 'sk_test_key') // Use your secret key
  .update(new URL(originalUrl).search) // Use the query string part of the URL
  .digest('base64'); // Convert the result to a base64 string

  const urlWithSignature = `${originalUrl}&signature=${encodeURIComponent(signature)}`; // Add the signature to the URL

  console.log(urlWithSignature); // Print the signed URL
  ```

  ```php PHP theme={null}
  <?php
    $host = 'https://buy-sandbox.moonpay.com';  // Base URL
    $query = '?apiKey=pk_test_key&currencyCode=eth&walletAddress=0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae';  // Query parameters

    $secretKey = 'sk_test_key';  // Your secret key

    // Create the HMAC SHA-256 hash and encode it in base64
    $signature = base64_encode(hash_hmac('sha256', $query, $secretKey, true));

    // URL encode the signature
    $encodedSignature = urlencode($signature);

    // Combine the base URL, query parameters, and the signature
    $signedUrl = $host . $query . "&signature=" . $encodedSignature;

    echo $signedUrl;  // Print the signed URL
  ?>
  ```
</CodeGroup>

<Warning>
  Attention: The API gateway of some cloud providers change your parameter's
  order, resulting in a failed signature validation.
</Warning>
