Skip to content

HMAC Authentication

HMAC (Hash-based Message Authentication Code) provides an additional layer of security for API requests through cryptographic signatures. When enabled, all requests must include signatures that verify both authenticity and integrity.

Overview

HMAC authentication is an optional security layer that can be enabled on a per-organization basis. It ensures that:

  • Requests come from legitimate sources
  • Data hasn't been tampered with during transmission
  • Requests are fresh (timestamp validation prevents replay attacks)

Key Benefits

BenefitDescription
Message IntegrityCryptographic proof that request data is unmodified
AuthenticationVerifies the request comes from a legitimate source
Replay ProtectionTimestamp validation prevents replay attacks
FlexibleCan be enabled/disabled per organization

How HMAC Works

Authentication Flow

  1. Client Preparation: Create request with current timestamp
  2. Signature Generation: Generate HMAC using secret key and request data
  3. Request Transmission: Send request with HMAC headers
  4. Server Validation: Server validates timestamp and signature
  5. Request Processing: If valid, server processes the request

Supported Algorithms

AlgorithmDescriptionOutput LengthRecommendation
sha256SHA-256 (Default)64 charactersRecommended for most use cases
sha512SHA-512128 charactersEnhanced security for sensitive operations

Required Headers

When HMAC is enabled, include these headers in every request:

HeaderDescriptionFormatExample
AuthorizationYour API keyBearer {api_key}Bearer flpk_live_abc123
X-FLUID-TimestampUnix timestampInteger string1692364800
X-FLUID-SignatureHMAC signature{algorithm}={signature}sha256=abc123...

Signature Generation

Step-by-Step Process

1. Create String-to-Sign

Combine the following elements with newline characters (\n):

HTTP_METHOD + "\n" + 
REQUEST_PATH + "\n" + 
TIMESTAMP + "\n" + 
SHA256_HASH_OF_REQUEST_BODY

Example for POST request:

POST
/api/v1/payment-providers/debit-requests/charge
1692364800
d0765f73cd5d1df39be353d538ea7c47a017d66a8bd001dc4707240dbb71e58c

2. Generate HMAC Signature

signature = HMAC_{ALGORITHM}(secret_key, string_to_sign)

3. Format Header Value

X-FLUID-Signature: sha256={signature}

Implementation Examples

The following bash script demonstrates HMAC signature generation. Implement similar logic in your preferred programming language.

bash
#!/bin/bash

# Configuration
API_KEY="your_api_key"
SECRET_KEY="your_secret_key"
ALGORITHM="sha256"
BASE_URL="https://api.fluid-network.com"

# Function to generate HMAC signature
generate_signature() {
    local method="$1"
    local path="$2"
    local timestamp="$3"
    local body="$4"
    
    # Create body hash
    local body_hash=$(echo -n "$body" | sha256sum | cut -d' ' -f1)
    
    # Create string to sign
    local string_to_sign="${method}
${path}
${timestamp}
${body_hash}"
    
    # Generate HMAC signature
    echo -n "$string_to_sign" | openssl dgst -$ALGORITHM -hmac "$SECRET_KEY" | cut -d' ' -f2
}

# Create request
METHOD="POST"
PATH="/api/v1/payment-providers/debit-requests/charge"
TIMESTAMP=$(date +%s)
BODY='{
  "phone_number": "+233241234567",
  "bank_identifier": "ECO",
  "amount": 100.00,
  "currency": "GHS",
  "narration": "Payment for Order #12345",
  "partner_reference": "partner_tx_123456"
}'

# Generate signature
SIGNATURE=$(generate_signature "$METHOD" "$PATH" "$TIMESTAMP" "$BODY")

# Make request
curl "${BASE_URL}${PATH}" \
  -X POST \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-FLUID-Timestamp: $TIMESTAMP" \
  -H "X-FLUID-Signature: $ALGORITHM=$SIGNATURE" \
  -H "Content-Type: application/json" \
  -d "$BODY"

Implementation Steps:

  1. Generate Timestamp:

    • Use current Unix timestamp (seconds since epoch)
    • Example: 1692364800
  2. Hash the Request Body:

    • Compute SHA-256 hash of the JSON body
    • Use empty string '' if no body (GET requests)
    • Result is hexadecimal string
  3. Create String-to-Sign:

    • Concatenate: METHOD\nPATH\nTIMESTAMP\nBODY_HASH
    • Use literal newline characters (\n)
    • Method must be uppercase (e.g., POST, GET)
  4. Generate HMAC:

    • Use HMAC-SHA256 (or SHA512) with your secret key
    • Input is the string-to-sign
    • Output is hexadecimal signature
  5. Add Headers:

    • Authorization: Bearer {api_key}
    • X-FLUID-Timestamp: {timestamp}
    • X-FLUID-Signature: sha256={signature}

Why This Matters:

HMAC signatures prove that:

  • The request came from someone with your secret key (authentication)
  • The request data hasn't been modified in transit (integrity)
  • The request is recent and not a replay of an old request (freshness)

Configuration

Timestamp Window

The timestamp window defines how long a signed request remains valid. Default: 300 seconds (5 minutes).

Recommendations:

  • Minimum: 60 seconds (allows for minor clock skew)
  • Maximum: 600 seconds (10 minutes)
  • Production: 300 seconds (balanced security and usability)

Clock Synchronization:

Ensure your servers are synchronized with NTP to avoid timestamp validation failures.

Error Responses

Missing HMAC Headers

json
{
  "success": false,
  "error": {
    "code": 1401,
    "message": "HMAC signature required",
    "category": "authentication",
    "severity": "high"
  },
  "details": "Request missing required HMAC headers",
  "meta": {
    "timestamp": "2025-01-18T10:30:00Z",
    "request_id": "req_abc123"
  }
}

Invalid Signature

json
{
  "success": false,
  "error": {
    "code": 1401,
    "message": "Invalid HMAC signature",
    "category": "authentication",
    "severity": "high"
  },
  "details": "HMAC signature verification failed"
}

Expired Timestamp

json
{
  "success": false,
  "error": {
    "code": 1401,
    "message": "Request timestamp expired",
    "category": "authentication",
    "severity": "high"
  },
  "details": "Request timestamp is outside the allowed window"
}

Invalid Timestamp Format

json
{
  "success": false,
  "error": {
    "code": 1400,
    "message": "Invalid timestamp format",
    "category": "validation",
    "severity": "medium"
  },
  "details": "Timestamp must be a valid Unix timestamp"
}

Troubleshooting

Common Issues

1. Clock Skew Problems

Symptoms: "Request timestamp expired" errors despite recent requests

Solutions:

  • Synchronize server clocks with NTP
  • Use pool.ntp.org or similar reliable time source
  • Consider a slightly larger timestamp window (e.g., 600 seconds)

2. Incorrect String-to-Sign

Symptoms: "Invalid HMAC signature" errors

Checklist:

  • ✅ HTTP method is uppercase (POST, not post)
  • ✅ Path includes query parameters if present
  • ✅ Timestamp matches the header value exactly
  • ✅ Body hash is computed correctly
  • ✅ Line endings are \n (not \r\n)

3. Wrong Secret Key

Symptoms: Consistent signature validation failures

Solutions:

  • Verify you're using the HMAC secret key, not the API key
  • Check for trailing spaces or hidden characters
  • Ensure UTF-8 encoding
  • Request new secret key from FLUID support if needed

Debugging Tips

Enable detailed logging during development:

javascript
console.log('Method:', method);
console.log('Path:', path);
console.log('Timestamp:', timestamp);
console.log('Body Hash:', bodyHash);
console.log('String to Sign:', stringToSign);
console.log('Generated Signature:', signature);

Security Warning: Never log secret keys or signatures in production environments.

Best Practices

1. Secret Key Management

  • Store secret keys in environment variables or secret vaults
  • Never commit secret keys to version control
  • Rotate secret keys every 3-6 months
  • Use different keys for sandbox and production

2. Implementation Security

  • Always use HTTPS for API communications
  • Implement reasonable timestamp windows (300-600 seconds)
  • Log HMAC validation failures for security monitoring
  • Don't expose sensitive information in error messages

3. Testing

Test your HMAC implementation thoroughly:

  • Verify signature generation with known inputs
  • Test with expired timestamps
  • Test with invalid signatures
  • Test with missing headers

Enabling HMAC

To enable HMAC authentication for your organization:

  1. Contact Support: Email support@fluidnetwork.africa
  2. Request HMAC: Specify your organization and desired algorithm
  3. Receive Secret Key: FLUID will provide your HMAC secret key
  4. Update Integration: Implement HMAC signature generation
  5. Test in Sandbox: Thoroughly test before production
  6. Go Live: Enable HMAC in production

Next Steps

Support

Need help with HMAC authentication?