Files
fitness/backend/API_HMAC_GUIDE.md
2026-10-04 00:19:45 +03:00

6.0 KiB

/**

  • HMAC Authentication Implementation Guide
  • For Fitness Tracking App API
  • This document explains how to generate HMAC signatures for API requests */

HMAC Request Signing Process

Overview

All API requests must include HMAC-SHA256 signatures for authentication and integrity verification.

Required Headers

X-API-Key: <user_api_key>
X-Signature: <hmac_signature>
X-Timestamp: <unix_timestamp>

Signature Generation Algorithm

1. Create the message to sign

message = timestamp + "|" + api_key + "|" + raw_request_body

2. Generate HMAC-SHA256

signature = HMAC-SHA256(message, api_secret)

3. Encode as hex string

hex_signature = hex_encode(signature)

PHP Implementation Example

$api_key = 'your_api_key_here';
$api_secret = 'your_api_secret_here';
$timestamp = time();
$request_body = json_encode([
    'workout_type' => 'running',
    'distance_meters' => 5000,
    'duration_seconds' => 1800,
    // ... other fields
]);

// Generate signature
$message = $timestamp . '|' . $api_key . '|' . $request_body;
$signature = hash_hmac('sha256', $message, $api_secret);

// Make request with headers
$headers = [
    'Content-Type: application/json',
    'X-API-Key: ' . $api_key,
    'X-Signature: ' . $signature,
    'X-Timestamp: ' . $timestamp
];

$ch = curl_init('https://your-api.com/api/v1/workouts');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

Dart/Flutter Implementation Example

import 'package:crypto/crypto.dart';

String generateHmacSignature(
  String apiKey,
  String apiSecret,
  String payload,
  int timestamp,
) {
  final message = '$timestamp|$apiKey|$payload';
  final hmac = Hmac(sha256, utf8.encode(apiSecret));
  final digest = hmac.convert(utf8.encode(message));
  return digest.toString();
}

// Usage:
final timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;
final payload = jsonEncode({
  'workout_type': 'running',
  'distance_meters': 5000,
  // ...
});

final signature = generateHmacSignature(
  apiKey,
  apiSecret,
  payload,
  timestamp,
);

// Send request with headers
final response = await http.post(
  Uri.parse('https://your-api.com/api/v1/workouts'),
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': apiKey,
    'X-Signature': signature,
    'X-Timestamp': '$timestamp',
  },
  body: payload,
);

Payload Format

Workout Submission Payload

{
  "workout_type": "running|walking",
  "distance_meters": 5000,
  "duration_seconds": 1800,
  "elevation_gain_meters": 150,
  "elevation_loss_meters": 100,
  "calories_burned": 350.5,
  "max_speed_mps": 4.5,
  "route_polyline": "encoded_polyline_string",
  "start_time": "2026-04-21T14:30:00.000Z",
  "end_time": "2026-04-21T14:45:00.000Z",
  "weather_condition": "sunny",
  "temperature_celsius": 22.5,
  "notes": "Great workout!",
  "is_public": false,
  "segments": [
    {
      "duration_seconds": 600,
      "distance_meters": 1500,
      "index_in_polyline": 0
    }
  ]
}

Security Considerations

  1. Timestamp Validation: Requests must be within 5 minutes of server time
  2. Timing-Safe Comparison: Signatures are verified using constant-time comparison
  3. Replay Attack Prevention: Each request timestamp is validated
  4. HTTPS Only: Always use HTTPS in production
  5. Secret Rotation: Implement API secret rotation periodically
  6. Rate Limiting: Consider implementing rate limits per API key

Error Responses

401 Unauthorized

{
  "status": "error",
  "error": "Invalid API key",
  "timestamp": "2026-04-21T14:45:00.000Z"
}

400 Bad Request

{
  "status": "error",
  "error": "Missing required authentication headers",
  "timestamp": "2026-04-21T14:45:00.000Z"
}

422 Unprocessable Entity

{
  "status": "error",
  "error": "Validation failed: distance_meters must be between 100 and 100000",
  "timestamp": "2026-04-21T14:45:00.000Z"
}

Success Response (201 Created)

{
  "status": "success",
  "data": {
    "workout_id": 123,
    "workout_uuid": "550e8400-e29b-41d4-a716-446655440000",
    "message": "Workout submitted successfully",
    "timestamp": "2026-04-21T14:45:00.000Z"
  }
}

API Rate Limits

  • 100 requests per minute per API key
  • 5000 requests per day per API key
  • Rate limit headers included in response:
    • X-RateLimit-Limit: 100
    • X-RateLimit-Remaining: 95
    • X-RateLimit-Reset: 1629907200

Testing HMAC Signature Generation

Using cURL with debugging:

#!/bin/bash

API_KEY="your_api_key"
API_SECRET="your_api_secret"
TIMESTAMP=$(date +%s)
ENDPOINT="https://your-api.com/api/v1/workouts"
PAYLOAD='{"workout_type":"running","distance_meters":5000,"duration_seconds":1800,"elevation_gain_meters":0,"elevation_loss_meters":0,"calories_burned":350,"max_speed_mps":4.5,"route_polyline":"abc123","start_time":"2026-04-21T14:00:00Z","end_time":"2026-04-21T14:30:00Z"}'

MESSAGE="${TIMESTAMP}|${API_KEY}|${PAYLOAD}"
SIGNATURE=$(echo -n "$MESSAGE" | openssl dgst -sha256 -hmac "$API_SECRET" | awk '{print $NF}')

echo "Timestamp: $TIMESTAMP"
echo "Signature: $SIGNATURE"
echo "Payload: $PAYLOAD"

curl -X POST "$ENDPOINT" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $API_KEY" \
  -H "X-Signature: $SIGNATURE" \
  -H "X-Timestamp: $TIMESTAMP" \
  -d "$PAYLOAD"

API Key Management

Getting Your API Credentials

Users receive their API credentials upon registration:

  • API Key (64 character hex string)
  • API Secret (64 character hex string)

Regenerating Credentials

API credentials can be regenerated from the user settings panel (invalidates old credentials immediately).

Best Practices

  1. Store credentials securely (use OS keychain/secure storage)
  2. Never commit credentials to version control
  3. Use environment variables or secure configuration
  4. Rotate credentials periodically
  5. Monitor API logs for suspicious activity
  6. Use separate credentials for different apps/devices