DEV Community

Cover image for Understanding Rapyd API Signatures
Drew Harris for Rapyd

Posted on • Edited on • Originally published at community.rapyd.net

Understanding Rapyd API Signatures

APIs serve as the backbone for modern applications, allowing seamless interactions between different systems and facilitating the flow of data and transactions. This makes it all the more necessary to secure these APIs to prevent unauthorized access to privilege and data. API signatures are a useful way to ensure that access to these APIs remains secure.

API signatures serve as digital fingerprints that help verify the origin of API requests and the integrity of data being exchanged through them. In this article, you will learn in detail what API signatures are in the context of Rapyd, a global fintech platform that allows you to set up payments, disbursements, and the like in your software applications.

API Security Fundamentals

While APIs are quite crucial to the smooth functioning of apps on the web, they introduce a host of security risks for the app owners:

  • Unauthorized access: Malicious actors may attempt to gain unauthorized access to your APIs, potentially exposing sensitive data or disrupting services.
  • Data exposure: Inadequate security measures can lead to the unintentional exposure of sensitive data, risking breaches of user privacy and regulatory noncompliance.
  • Injection attacks: Attackers may use malicious input, such as SQL injection or cross-site scripting (XSS), to compromise your API's integrity and lead to data manipulation or theft.
  • Denial-of-service (DoS) attacks: Attackers may flood your API with requests, causing service disruptions and potentially overwhelming your servers.

To mitigate these risks and reinforce your API's protection against such threats, you should consider implementing the following standard API security practices:

  • Use secure protocols for communication: Employ HTTPS to encrypt data in transit, ensuring that data exchanged between the client and server remains confidential and tamper-proof.
  • Validate and sanitize all user input: Ensure that all user inputs are rigorously checked and cleansed of any malicious content before being processed by your systems.
  • Consider implementing rate limiting and throttling: Prevent abuse and DoS attacks by limiting the number of requests a client can make within a specified time frame.
  • Implement proper error-handling mechanisms: Error messages should provide minimal information to clients, revealing as little about the internal workings of your system as possible.
  • Use strong authentication/authorization constructs, such as API keys and request signatures: Utilize robust authentication mechanisms like API keys, OAuth tokens, or request signatures to verify the identity of clients and restrict access to authorized users.

Rapyd API signatures are a strong authentication construct for verifying the integrity of requests coming from client devices.

What Is a Rapyd API Signature?

As mentioned, Rapyd API signatures are digital fingerprints used to verify the origin and authenticity of data being exchanged between two virtual entities. They act as a cryptographic stamp of approval, assuring both parties that the information transmitted has not been tampered with and comes from a trusted source.

Using an API signature when interacting with the Rapyd API has the following advantages:

  • Identity verification: It helps identify the user who is accessing the API and provides them with relevant data.
  • Data tamper protection: It helps protect data from being tampered with while it travels across the network. Tampering the data now requires the signature to be recreated, which is not possible without the secret key that is not transmitted with the request; hence, security is enhanced.

What Makes a Rapyd API Signature?

A Rapyd API signature takes in a significant number of input parameters to ensure the maximum possible security for API requests. Here's what the pseudocode for calculating a Rapyd API signature looks like:

signature = BASE64 ( HASH ( http_method + url_path + salt + timestamp + access_key + secret_key + body_string ) )

BASE64() and HMAC() are functions, while http_method, url_path, salt, timestamp, access_key, secret_key, and body_string are values required to generate the signature. The + operator stands for the concatenation operation here to join the various values together and form one common string that the functions can process.

BASE64() and HMAC() are two cryptographic functions commonly used in software development and security to perform specific tasks related to data encoding and authentication.

Base64 is an encoding method that transforms binary data into a text-based format, primarily consisting of alphanumeric characters and a few special characters. It's often used to represent binary data, such as images, documents, or binary files, in a format that is safe for transmission over text-based protocols, like email or HTTP. Base64 encoding doesn't provide encryption or security; it is merely a way to represent binary data as text.

HMAC is a message authentication code generated using a cryptographic hash function (such as an implementation of the popular cryptographic algorithm SHA-256). It's used to verify the authenticity and integrity of a message or data by generating a hash value based on the message and a secret key. HMAC prevents unauthorized access and tampering during data transmission or storage. It's commonly used in authentication mechanisms, such as API authentication, digital signatures, and secure communication protocols like SSL/TLS.

Regarding the values, here is a quick gist of what each one stands for:

  • http_method: The HTTP method used in the request. Make sure to pass it in, in lowercase letters (such as 'get' instead of 'GET').
  • url_path: The portion of the API URL after the base URI (which is https://api.rapyd.net) denoting the Rapyd service you are trying to access. The URL path must start with /v1.
  • salt: A random string for each request. The recommended length for this string is eight to sixteen characters.
  • timestamp: The time at which the request was generated, in Unix time (seconds). Please note that the Rapyd platform is synchronized to the current time as defined by public NTP servers. The timestamp must be equal to the current time or less than 60 seconds before it.
  • access_key: A unique sensitive string assigned by Rapyd for each user. You can get this value from the Client Portal.
  • secret_key: A unique sensitive string for each user assigned by Rapyd. The secret key is like a password and is transmitted only as part of the calculated signature. Make sure you don't share it with your customers or partners, and do not transmit it in plaintext. You can get this value from the Client Portal.
  • body_string: A valid JSON string (relevant to requests that contain a body) representing the body of the request being sent. If the body is empty, it must be empty in the request and in the signature calculation and not empty curly braces {}.

Note: After creating the digest, you'll need to convert it into a hex string. Then, you must manually encode the hex string into a Base64 string. If you try to directly encode the raw digest into Base64, it will result in authentication failure with Rapyd servers. This is because Rapyd requires the signature to be generated in the order of HMAC digest > Hex > Base64.

Creating Rapyd API Signatures in Code

This section will list a range of code snippets across languages that you can plug into your apps so that you can get started with generating Rapyd API signatures quickly and easily.

All of the methods listed below will take in the required values (http_method, url_path, salt, timestamp, access_key, secret_key, and body_string) through the function parameters and return the generated Rapyd API signature as a string.

Node.js

Here's the method that you can use in Node.js to generate Rapyd API signatures:

const crypto = require('crypto');

function generateSignature(httpMethod, urlPath, salt, timestamp, accessKey, secretKey, body) {
    try {
        let bodyString = "";
        if (body) {
            bodyString = JSON.stringify(body);      
            bodyString = bodyString == "{}" ? "" : bodyString; // If body was empty, the body string should also be empty (and not curly braces)
        }

        let toSign = httpMethod.toLowerCase() + urlPath + salt + timestamp + accessKey + secretKey + bodyString;

        let hash = crypto.createHmac('sha256', secretKey);
        hash.update(toSign);

        const signature = Buffer.from(hash.digest("hex")).toString("base64")

        return signature;
    } catch (error) {
        console.error("An error occurred when generating the signature");
        throw error;
    }
}
Enter fullscreen mode Exit fullscreen mode

Java

Here's the Java code to help you quickly generate Rapyd signatures easily:

public static String generateSignature(String httpMethod, String urlPath, String salt, String timestamp, String accessKey, String secretKey, String body) {
        try {
            String toSign = httpMethod + urlPath + salt + timestamp + accessKey + secretKey + body;

            String StrhashCode = hmacDigest(toSign, secretKey, "HmacSHA256");

            String signature = Base64.getEncoder().encodeToString(StrhashCode.getBytes());

            return signature;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

public static String hmacDigest(String msg, String keyString, String algo) {
    String digest = null;
    try {
        SecretKeySpec key = new SecretKeySpec((keyString).getBytes("ASCII"), algo);
        Mac mac = Mac.getInstance(algo);
        mac.init(key);

        byte[]bytes = mac.doFinal(msg.getBytes("UTF-8"));

        StringBuffer hash = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                hash.append('0');
            }
            hash.append(hex);
        }
        digest = hash.toString();
    } catch (Exception e) {
        e.printStackTrace();
    }

    return digest;
}
Enter fullscreen mode Exit fullscreen mode

Kotlin

The Java code has been rewritten in Kotlin to help you generate Rapyd signatures easily in Kotlin:

import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import java.util.Base64

fun generateSignature(httpMethod: String, urlPath: String, salt: String, timestamp: String, accessKey: String, secretKey: String, body: String): String? {
    try {
        val toSign = httpMethod + urlPath + salt + timestamp + accessKey + secretKey + body
        val StrhashCode = hmacDigest(toSign, secretKey, "HmacSHA256")
        val signature = Base64.getEncoder().encodeToString(StrhashCode.toByteArray())
        return signature
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return null
}

fun hmacDigest(msg: String, keyString: String, algo: String): String? {
    var digest: String? = null
    try {
        val key = SecretKeySpec(keyString.toByteArray(StandardCharsets.US_ASCII), algo)
        val mac = Mac.getInstance(algo)
        mac.init(key)
        val bytes = mac.doFinal(msg.toByteArray(StandardCharsets.UTF_8))
        val hash = StringBuilder()
        for (i in bytes.indices) {
            val hex = Integer.toHexString(0xFF and bytes[i].toInt())
            if (hex.length == 1) {
                hash.append('0')
            }
            hash.append(hex)
        }
        digest = hash.toString()
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return digest
}
Enter fullscreen mode Exit fullscreen mode

Swift

Here's a code snippet that follows the same logic as the previous code snippets to help you generate Rapyd API signatures in Swift:

import Foundation
import CommonCrypto

func generateRapydAPISignature(httpMethod: String, urlPath: String, salt: String, timeStamp: String, accessKey: String, secretKey: String, requestBody: String) -> String {

    // Create the string to be signed
    let toSign = "\(httpMethod.lowercased())\(urlPath)\(salt)\(timeStamp)\(accessKey)\(secretKey)\(requestBody)"

    guard let secretKeyData = secretKey.data(using: .utf8) else {
        fatalError("Failed to convert the secret key to Data")
    }


    var hmacContext = CCHmacContext()
    CCHmacInit(&hmacContext, CCHmacAlgorithm(kCCHmacAlgSHA256), (secretKeyData as NSData).bytes, secretKeyData.count)
    CCHmacUpdate(&hmacContext, toSign, toSign.count)

    var hmacDigest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
    CCHmacFinal(&hmacContext, &hmacDigest)

    let signatureData = Data(hmacDigest)

    // Convert the digest to hex string
    let signatureHex = signatureData.map { String(format: "%02hhx", $0) }.joined()

    // Encode the hex string to Base64
    guard let signature = signatureHex.data(using: .utf8)?.base64EncodedString() else {
        fatalError("Failed to convert the hash string to base64")
    }

    return signature
}


Enter fullscreen mode Exit fullscreen mode

PHP

Here's a PHP code snippet to create Rapyd API signatures easily:

function generateRapydAPISignature($httpMethod, $urlPath, $salt, $timestamp, $accessKey, $secretKey, $requestBody) {

    // Create the string to be signed
    $toSign = "$httpMethod$urlPath$salt$timestamp$accessKey$secretKey$requestBody";

    // Calculate the HMAC-SHA256 hash using the secret key
    $hashSignature = hash_hmac('sha256', $toSign, $secretKey);
    $signature = base64_encode($hashSignature);

    return $signature;
}

Enter fullscreen mode Exit fullscreen mode

You'll find all these code snippets in this GitHub repository. You will also find code snippets for more languages in the Rapyd docs.

Code

Get the code, build something amazing with the Rapyd API, and share it with us here in the developer community. Hit reply below if you have questions or comments.

Top comments (0)