tencent/tls-sig-api-v2
Official PHP SDK for Tencent Cloud's TLS Sig API v2 that generates UserSig authentication signatures for TRTC, IM, and other real-time communication services. It handles HMAC-SHA256 signing, base64 encoding, and expiry so your PHP backend can securely issue time-limited user credentials without expo...
tencent/tls-sig-api-v2 is a single-purpose library: it computes the UserSig (a signed JWT) that Tencent Cloud services such as TRTC, IM, and live streaming require to authenticate a user. That is the entire surface area — do not expect SDK wrappers, HTTP clients, or session management.
Install
composer require tencent/tls-sig-api-v2
Where to look first
Tencent\TLSSigAPIv2\TLSSigAPIv2.SDKAppID and secret key from the Tencent Cloud console (TRTC or IM application settings). The secret key is a server-side credential — never ship it to browsers or mobile apps.Minimal first use case
Generate a signature for a user when they authenticate against your own backend:
use Tencent\TLSSigAPIv2\TLSSigAPIv2;
$api = new TLSSigAPIv2(
(int) config('services.tencent.sdk_app_id'),
config('services.tencent.secret_key')
);
$userSig = $api->genUserSig($userId); // default expiry, see below
Return $userSig to your frontend alongside your own auth token, and pass it into the Tencent client SDK's login({ sdkAppId, userId, userSig }) call. Keep the SDKAppID and the userId consistent between signature generation and the client login — a mismatch produces a login failure that looks like an auth error but is really a config error.
Wrap it in a dedicated service. The raw class takes constructor args you should not sprinkle through controllers. A thin Laravel service or a bound singleton keeps the key in config and makes the generation point swappable and testable:
class UserSignatureService
{
public function __construct(private TLSSigAPIv2 $api) {}
public function forUser(string $userId): string
{
return $this->api->genUserSig($userId);
}
}
Bind TLSSigAPIv2 in a service provider using config('services.tencent.*').
Generate server-side, on demand. The signature is a credential. The standard workflow is: user authenticates to your app → your backend mints the UserSig → the client hands it to the Tencent SDK. Never generate signatures in the browser or bundle the secret.
Choose expiry deliberately. The default expiry is long (on the order of 180 days in the upstream algorithm). For most applications that is too generous — Tencent's own guidance is to favour short-lived signatures and re-issue them. Practically: mint on login, and re-issue via a refresh endpoint if the session outlives the signature. Pass the expire argument explicitly rather than relying on the default so the value lives in your config, not the library.
Cache within the validity window when appropriate. If you generate a signature per request you are re-computing the same HMAC pointlessly. Cache the result keyed by userId for slightly less than its expiry (a Cache::remember with a TTL a few minutes under the signature lifetime is a common pattern). Invalidate the cache entry if you rotate the secret key.
Treat the secret key like any other secret. Load it from environment/config, exclude it from VCS, and support rotation — when rotated, old signatures remain valid until they expire, so allow overlap.
Local development ergonomics. Point different environments at different Tencent applications (dev/staging/prod) so that a leaked dev key is harmless and so test users don't pollute production analytics. Keep sdk_app_id and secret_key paired per environment.
Testing. Because the output is a deterministic function of (appId, key, userId, expiry), you can assert shape and stability in tests. Freeze time if your wrapper embeds generation timestamps, and assert that the signature verifies with a known-good reference implementation (Tencent publishes an online UserSig generator for exactly this).
firebase/php-jwt in your own code. If you need to inspect it, use Tencent's decoder.sdk_app_id and user_id yourself before calling; empty or malformed inputs can produce a signature that fails only later on the client.How can I help you explore Laravel packages today?