Widget - Sign a URL

Introduction

Signature parameters should be used when passing sensitive information. If the following URL parameters are present in the URL,

  • wallets
  • walletAddressTags
  • networkWallets

You can generate a signature for the URL on the server-side and append it to the URL. When a signature is provided, the validity of the query string is checked to ensure it hasn't been tampered with. If the signature is invalid for any reason, the transaction will be restricted during checkout.

If the URL contains sensitive data, including the signature is mandatory. You must sign the URL's query string using the provided secret key (a new secret key will be provided for signing URLs) and attach the generated signature as a query parameter when loading the widget inside an iframe or in standalone mode.

Current URL Structure

Here is an example of the current URL structure with parameters:

https://buy.onramper.com/?apiKey=pk_prod_01GQS0CRGNRTTGV3A0S3A0AEW4&country=nl&wallets=btc:1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71,eth:1Lbcfr7sAUTEFCgdQo3HTMTkV8LK4ZnX71&networkWallets=bitcoin:1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2,ethereum:1BvBMSEYstWetqTFn5wrwrhGFryetusJaNVN2&walletAddressTags=btc:1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2,eth:1BvBMSEYstWetqTFn5wrwrhGFryetusJaNVN2

In this example, wallets, networkWallets, and walletAddressTags contain sensitive data that should be protected with a signature.

How to Generate the Signature

  1. Prepare the String to be Signed

    First, you need to prepare the string to be signed. It's essential to follow the format below. The URL parameters we expect to be signed are wallets, walletAddressTags, and networkWallets. The signContent would be a subset of the URL, containing only the parameters we require.


    const signContent = 'wallets=btc:1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71,eth:1Lbcfr7sAUTEFCgdQo3HTMTkV8LK4ZnX71&networkWallets=ethereum:1BvBMSEYstWetqTFn5wrwrhGFryetusJaNVN2,bitcoin:1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2&walletAddressTags=btc:1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2,eth:1BvBMSEYstWetqTFn5wrwrhGFryetusJaNVN2'
    
  2. Sort the String Keys Alphabetically
    In signContent, string keys should be ordered alphabetically. If there are nested values, those keys should also be sorted alphabetically. Adhering to a common format helps reduce signature validation errors.

    You can use the following function to convert your input URL string to a valid format.


    function arrangeStringAlphabetically(inputString: string): string {
        // Parse the input string into an object
        const inputObject: { [key: string]: { [key: string]: string } } = {};
        inputString.split('&').forEach((pair) => {
            // Split each pair into key and value
            const [key, value] = pair.split('=');
            // Split the value into nested key-value pairs
            const nestedPairs = value.split(',');
            inputObject[key] = {}; // Initialize the nested object for the key
            nestedPairs.forEach((nestedPair) => {
                // Split each nested pair into nested key and value
                const [nestedKey, nestedValue] = nestedPair.split(':');
                // Assign the nested key-value pair to the nested object
                inputObject[key][nestedKey] = nestedValue;
            });
        });
    
        // Sort the keys of each nested object alphabetically
        for (const key in inputObject) {
            inputObject[key] = Object.fromEntries(Object.entries(inputObject[key]).sort());
        }
    
        // Sort the keys of the top-level object alphabetically
        const sortedKeys = Object.keys(inputObject).sort();
        const sortedObject: { [key: string]: { [key: string]: string } } = {};
        sortedKeys.forEach((key) => {
            sortedObject[key] = inputObject[key];
        });
    
        // Reconstruct the string from the sorted object
        let resultString = '';
        for (const key in sortedObject) {
            resultString += key + '='; // Append the key
            // Append nested key-value pairs, sorted alphabetically
            resultString += Object.entries(sortedObject[key]).map(([nestedKey, nestedValue]) => `${nestedKey}:${nestedValue}`).join(',');
            resultString += '&'; // Separate key-value pairs with '&'
        }
        resultString = resultString.slice(0, -1); // Remove the trailing '&'
    
        return resultString;
    }
    
  3. Generate the Signature
    After preparing the signContent, you can use HMAC with SHA256 digested to hex to generate a signature.


    Note: We will provide a separate secret key specifically for signing the signContent. Please contact our customer support for assistance in obtaining the key.


    import crypto from "crypto";
    
    function generateSignature(secretKey: string, data: string): string {
        const hmac = crypto.createHmac("sha256", secretKey);
        hmac.update(data);
        return hmac.digest("hex");
    }	 
    
  4. Append the Signature to the URL
    Once the signature is generated, it should be appended to the original URL with the query parameter signature.

    const originalUrl = 'https://buy.onramper.com/?apiKey=pk_prod_01GQS0CRGNRTTGV3A0S3A0AEW4&country=nl&wallets=btc:1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71,eth:1Lbcfr7sAUTEFCgdQo3HTMTkV8LK4ZnX71&networkWallets=bitcoin:1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2,ethereum:1BvBMSEYstWetqTFn5wrwrhGFryetusJaNVN2&walletAddressTags=btc:1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2,eth:1BvBMSEYstWetqTFn5wrwrhGFryetusJaNVN2';
    const signature = generateSignature(secretKey, signContent);
    const signedUrl = `${originalUrl}&signature=${signature}`;