263 lines
6.0 KiB
Markdown
263 lines
6.0 KiB
Markdown
/\*\*
|
|
|
|
- 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
|
|
|
|
```php
|
|
$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
|
|
|
|
```dart
|
|
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
|
|
|
|
```json
|
|
{
|
|
"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
|
|
|
|
```json
|
|
{
|
|
"status": "error",
|
|
"error": "Invalid API key",
|
|
"timestamp": "2026-04-21T14:45:00.000Z"
|
|
}
|
|
```
|
|
|
|
### 400 Bad Request
|
|
|
|
```json
|
|
{
|
|
"status": "error",
|
|
"error": "Missing required authentication headers",
|
|
"timestamp": "2026-04-21T14:45:00.000Z"
|
|
}
|
|
```
|
|
|
|
### 422 Unprocessable Entity
|
|
|
|
```json
|
|
{
|
|
"status": "error",
|
|
"error": "Validation failed: distance_meters must be between 100 and 100000",
|
|
"timestamp": "2026-04-21T14:45:00.000Z"
|
|
}
|
|
```
|
|
|
|
## Success Response (201 Created)
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```bash
|
|
#!/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
|