API Request Authentication (HMAC-SHA256)
All API requests to/api/* endpoints must include a valid LT-SIGNATURE header. This prevents unauthorized access to stream management functions.
How It Works
- Client Side: Compute HMAC-SHA256 hash of the raw request body using your
HMAC_SECRET - Encoding: Convert the hash to hexadecimal string
- Header: Include the hex string in the
LT-SIGNATUREheader - Server Side: Server recomputes the hash and compares it with the provided signature
Generating Signatures
The signature is computed as:Example Implementation
JavaScript/Node.js:Important Notes
- Body Format: The signature must be computed on the exact JSON string that will be sent (whitespace matters)
- Content-Type: Always use
application/json - Missing Header: Requests without
LT-SIGNATUREreturn400 Bad Request - Invalid Signature: Requests with invalid signatures return
403 Forbidden - GET Requests: Even GET requests (like
/api/status) require a signed body
Security Best Practices
- Store Secrets Securely: Never commit
HMAC_SECRETto version control - Use Environment Variables: Load secrets from environment variables or secret management systems
- Rotate Secrets: Periodically rotate your
HMAC_SECRETand update all clients - HTTPS Only: Always use HTTPS in production to protect secrets in transit
- Rate Limiting: Consider implementing rate limiting at the reverse proxy level
Stream Key Authentication (JWT)
When you start a stream, Livetran generates a JWT-based stream key that your encoder must use to connect via SRT.Stream Key Format
The stream key is formatted as:mode=publish: Indicates this is a publishing connectionrid={stream_id}: The resource ID (must match the stream_id)token={jwt_token}: The JWT token containing stream authentication
JWT Token Structure
The JWT token contains:- Claims:
stream_id: The stream identifier (must matchrid)exp: Expiration timestamp (2 hours from generation)
- Algorithm: HS256 (HMAC-SHA256)
- Secret: Uses
JWT_SECRETenvironment variable
Generating Stream Keys
Stream keys are automatically generated when you call/api/start-stream. The key is included in the SRT URL returned via webhook:
Using Stream Keys in OBS
- Settings → Stream
- Service: Custom
- Server:
srt://your-server-ip:12345 - Stream Key:
mode=publish,rid=my-stream,token=eyJhbGc...(the full streamid value)
Stream Key Validation
When an encoder connects, Livetran:- Parses the streamid parameter
- Extracts
ridandtoken - Verifies
ridmatches the expectedstream_id - Validates the JWT token:
- Checks signature using
JWT_SECRET - Verifies expiration (
expclaim) - Confirms
stream_idclaim matchesrid
- Checks signature using
- Accepts or rejects the connection
Token Expiration
- Default Expiration: 2 hours from generation
- Expired Tokens: Rejected with
REJ_BADSECRET - Renewal: Start a new stream to get a fresh token
Security Considerations
- Time-Limited: Tokens expire after 2 hours, limiting exposure window
- Stream-Specific: Each token is tied to a specific
stream_id - Cryptographically Secure: Uses HMAC-SHA256 for signature verification
- One-Time Use: While tokens can be reused during their validity period, starting a new stream generates a new token
Environment Variables
Both authentication mechanisms require environment variables:Generating Secure Secrets
Use cryptographically secure random generators: OpenSSL:Troubleshooting
”Missing Header for Verification!”
- Cause:
LT-SIGNATUREheader not included - Solution: Add the header with a valid signature
”Invalid Request”
- Cause: Signature doesn’t match request body
- Solution: Verify you’re signing the exact JSON body being sent
”REJ_BADSECRET” (SRT Connection Rejected)
- Cause: Invalid or expired stream key
- Solution:
- Verify the stream key format is correct
- Check if the token has expired (2-hour limit)
- Ensure
stream_idmatches theridin the stream key - Verify
JWT_SECRETmatches between generation and validation
”Token expired”
- Cause: JWT token has passed its expiration time
- Solution: Start a new stream to get a fresh token
Testing Authentication
You can test HMAC signing using the helper script indocs/helpers/hmac-gen.js:
LT-SIGNATURE header.