English
English
Appearance
English
English
Appearance
Complete specification of all HTTP headers used in HMAC authentication.
All authenticated requests must include these headers:
Contains the HMAC signature and credential information.
Format:
HMAC-SHA256 CredentialType={type}, CredentialId={id}, SignedHeaders={headerList}, Signature={hexSignature}Example:
HMAC-SHA256 CredentialType=service, CredentialId=external-system-client, SignedHeaders=x-date;x-request-id;x-client-type, Signature=3c92776baecac9a2f88170cc8a9ed1122c7bb92d64eacbcee578c436e7e47a34Components:
| Component | Description | Example |
|---|---|---|
CredentialType | Type of credential | service or user |
CredentialId | Credential identifier | external-system-client or john@example.com |
SignedHeaders | List of headers included in signature | x-date;x-request-id;x-client-type |
Signature | HMAC-SHA256 signature (hex) | 3c92776baecac9a2f88170cc... |
⚠️ Header Format Rules:
HMAC-SHA256service or userRequest timestamp in ISO 8601 format (UTC timezone).
Format: YYYY-MM-DDTHH:mm:ssZ
Example: 2025-10-14T03:52:12Z
Rules:
Z)Valid formats:
✅ X-Date: 2025-10-14T03:52:12Z
✅ X-Date: 2025-10-14T03:52:12.000Z
❌ X-Date: 2025-10-14T10:52:12+07:00 (not UTC)
❌ X-Date: 2025-10-14 03:52:12 (wrong format)Generation examples:
TypeScript:
const xDate = new Date().toISOString();
// Output: 2025-10-14T03:52:12.123ZPython:
from datetime import datetime, timezone
x_date = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
# Output: 2025-10-14T03:52:12ZGo:
import "time"
xDate := time.Now().UTC().Format(time.RFC3339)
// Output: 2025-10-14T03:52:12ZUnique identifier for request tracing and debugging.
Format: UUID v4 (lowercase with hyphens)
Example: bf6c5652-9656-4167-b1d4-10c690a72102
Rules:
Valid formats:
✅ X-Request-Id: bf6c5652-9656-4167-b1d4-10c690a72102
❌ X-Request-Id: BF6C5652-9656-4167-B1D4-10C690A72102 (uppercase)
❌ X-Request-Id: bf6c56529656416b1d410c690a72102 (no hyphens)
❌ X-Request-Id: 123456 (not UUID)Generation examples:
TypeScript:
import crypto from 'crypto';
const xRequestId = crypto.randomUUID();
// Output: bf6c5652-9656-4167-b1d4-10c690a72102Python:
from uuid import uuid4
x_request_id = str(uuid4())
# Output: bf6c5652-9656-4167-b1d4-10c690a72102Go:
import "github.com/google/uuid"
xRequestId := uuid.New().String()
// Output: bf6c5652-9656-4167-b1d4-10c690a72102Indicates the type of client making the request.
Format: String enum
Allowed values:
| Value | Description | Use Case |
|---|---|---|
service | Backend service/API | System-to-system integration |
web | Web browser | Web application frontend |
mobile | Mobile app | iOS/Android applications |
cli | Command-line tool | Scripts and CLI tools |
worker | Background worker | Async jobs and scheduled tasks |
Example: service
Rules:
Valid examples:
✅ X-Client-Type: service
✅ X-Client-Type: web
✅ X-Client-Type: mobile
❌ X-Client-Type: Service (wrong case)
❌ X-Client-Type: api (not allowed)
❌ X-Client-Type: custom (not allowed)These headers are required only in specific scenarios:
Tenant identifier for multi-tenant requests.
Format: String (alphanumeric, hyphens, underscores)
Example: tenantA or isp-branch-001
Required when:
CredentialType=user)Not required when:
CredentialType=service)Valid examples:
✅ X-Tenant-Id: tenantA
✅ X-Tenant-Id: isp-branch-001
✅ X-Tenant-Id: customer_123
❌ X-Tenant-Id: tenant@123 (special chars)
❌ X-Tenant-Id: tenant 123 (spaces)Usage example:
// Service credential (X-Tenant-Id not needed)
const serviceHeaders = {
'Authorization': 'HMAC-SHA256 CredentialType=service, CredentialId=external-system-client, SignedHeaders=x-date;x-request-id;x-client-type, Signature=...',
'X-Date': '2025-10-14T03:52:12Z',
'X-Request-Id': 'bf6c5652-9656-4167-b1d4-10c690a72102',
'X-Client-Type': 'service'
};
// User credential (X-Tenant-Id required)
const userHeaders = {
'Authorization': 'HMAC-SHA256 CredentialType=user, CredentialId=john@example.com, SignedHeaders=x-date;x-tenant-id;x-request-id;x-client-type, Signature=...',
'X-Date': '2025-10-14T03:52:12Z',
'X-Request-Id': 'bf6c5652-9656-4167-b1d4-10c690a72102',
'X-Client-Type': 'web',
'X-Tenant-Id': 'tenantA' // ✅ Required for user credentials
};These standard headers should also be included:
Specifies the media type of the request body.
Format: MIME type
Common values:
| Value | Usage |
|---|---|
application/json | JSON data (most common) |
application/x-www-form-urlencoded | Form data |
multipart/form-data | File uploads |
text/plain | Plain text |
Example: application/json
Rules:
Target server hostname.
Format: hostname or hostname:port
Example: olt.remala.local
Rules:
⚠️ Important: Header names in canonical request must be lowercase, but actual HTTP headers can be any case.
// In canonical request (for signature calculation)
'x-date:2025-10-14T03:52:12Z' // ✅ Must be lowercase
// In actual HTTP request (both work)
'X-Date: 2025-10-14T03:52:12Z' // ✅ OK
'x-date: 2025-10-14T03:52:12Z' // ✅ OKHeaders in SignedHeaders parameter must follow the exact order required by server:
✅ SignedHeaders=x-date;x-request-id;x-client-type
❌ SignedHeaders=x-client-type;x-date;x-request-idFor user credentials (with X-Tenant-Id):
✅ SignedHeaders=x-date;x-tenant-id;x-request-id;x-client-type
❌ SignedHeaders=x-client-type;x-date;x-request-id;x-tenant-idPOST /api/devices HTTP/1.1
Host: olt.remala.local
Authorization: HMAC-SHA256 CredentialType=service, CredentialId=external-system-client, SignedHeaders=x-date;x-request-id;x-client-type, Signature=3c92776baecac9a2f88170cc8a9ed1122c7bb92d64eacbcee578c436e7e47a34
X-Date: 2025-10-14T03:52:12Z
X-Request-Id: bf6c5652-9656-4167-b1d4-10c690a72102
X-Client-Type: service
Content-Type: application/json
{"device_id": "OLT-001", "action": "reboot"}GET /api/onu/unconfigured HTTP/1.1
Host: olt.remala.local
Authorization: HMAC-SHA256 CredentialType=user, CredentialId=admin@telkom.com, SignedHeaders=x-date;x-tenant-id;x-request-id;x-client-type, Signature=5d83ac7f3bd1e8a9c2f77e1a9c8e6f4b2d91c5a8e3f7d6b4a2c9e8f1d5a7c3b9
X-Date: 2025-10-14T03:52:12Z
X-Request-Id: af7d4523-8765-4278-a2e5-21d801b83456
X-Client-Type: web
X-Tenant-Id: isp-telkomError Response:
{
"error": "unauthorized",
"message": "Missing required headers: X-Date, X-Request-Id",
"code": 401
}Solution: Ensure all required headers are present in the request.
Check:
Error Response:
{
"error": "bad_request",
"message": "Invalid X-Date format. Expected ISO 8601 (UTC)",
"code": 400
}Solution: Check header format matches specification.
Common issues:
Error Response:
{
"error": "unauthorized",
"message": "Invalid Authorization format",
"code": 401
}Solution: Check Authorization header structure.
Common mistakes:
❌ Authorization: HMAC-SHA256 Credential=service:external-system-client, ...
(Using old format Credential=type:id instead of CredentialType, CredentialId)
✅ Authorization: HMAC-SHA256 CredentialType=service, CredentialId=external-system-client, ...
(Correct format with separate CredentialType and CredentialId)Error Response:
{
"error": "unauthorized",
"message": "Request timestamp expired. Max allowed: 5 minutes",
"code": 401
}Solution:
Debug steps:
// Log timestamp being sent
console.log('Sending timestamp:', new Date().toISOString());
// Check server time difference
const serverTime = response.headers['date'];
const clientTime = new Date().toISOString();
console.log('Time diff:', new Date(serverTime) - new Date(clientTime));Error Response:
{
"error": "unauthorized",
"message": "Signature verification failed",
"code": 401
}Common causes:
Solution:
// ✅ Correct (server order)
SignedHeaders=x-date;x-request-id;x-client-type
// ❌ Wrong order
SignedHeaders=x-client-type;x-date;x-request-id
// ❌ Missing header
SignedHeaders=x-date;x-tenant-id;x-request-id;x-client-type
// But X-Tenant-Id not sent in actual request| Header | Required | Format | Example |
|---|---|---|---|
Authorization | ✅ Always | HMAC-SHA256 format | HMAC-SHA256 CredentialType=service, CredentialId=external-system-client, ... |
X-Date | ✅ Always | ISO 8601 (UTC) | 2025-10-14T03:52:12Z |
X-Request-Id | ✅ Always | UUID v4 | bf6c5652-9656-4167-b1d4-10c690a72102 |
X-Client-Type | ✅ Always | Enum | service, web, mobile, cli, worker |
X-Tenant-Id | ⚠️ User credentials only | Alphanumeric | tenantA |
Content-Type | ⚠️ With body | MIME type | application/json |
Host | ✅ Always | Hostname | olt.remala.local |
HMAC-SHA256 CredentialType=service, CredentialId={service-slug}, SignedHeaders={headers}, Signature={signature}Example:
HMAC-SHA256 CredentialType=service, CredentialId=external-system-client, SignedHeaders=x-date;x-request-id;x-client-type, Signature=3c92776b...SignedHeaders for service:
x-date;x-request-id;x-client-typeHMAC-SHA256 CredentialType=user, CredentialId={user-email}, SignedHeaders={headers}, Signature={signature}Example:
HMAC-SHA256 CredentialType=user, CredentialId=admin@telkom.com, SignedHeaders=x-date;x-tenant-id;x-request-id;x-client-type, Signature=5d83ac7f...SignedHeaders for user:
x-date;x-tenant-id;x-request-id;x-client-typeAdditional required header:
X-Tenant-Id must be present in the request