6.0 KiB
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
- Timestamp Validation: Requests must be within 5 minutes of server time
- Timing-Safe Comparison: Signatures are verified using constant-time comparison
- Replay Attack Prevention: Each request timestamp is validated
- HTTPS Only: Always use HTTPS in production
- Secret Rotation: Implement API secret rotation periodically
- 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: 100X-RateLimit-Remaining: 95X-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
- Store credentials securely (use OS keychain/secure storage)
- Never commit credentials to version control
- Use environment variables or secure configuration
- Rotate credentials periodically
- Monitor API logs for suspicious activity
- Use separate credentials for different apps/devices