Some widget use cases require validated data integrity from your backend to prevent misuse by end-users or malicious actors. In such cases, you need to create and sign a JSON Web Token (JWT) using a public/private key pair, and pass that token to widgets as properties.
Before starting this tutorial, ensure you have:
jsonwebtoken for Node.js)The following diagram illustrates the JWT authentication flow:
Generate a pair of RSA keys using the OpenSSL toolkit:
# Generate private key (2048-bit RSA)
openssl genrsa -out rsa-private.pem 2048
# Extract public key from private key
openssl rsa -in rsa-private.pem -pubout -outform PEM -out rsa-public.pemThis creates two files:
rsa-private.pem - Keep this secure on your backend serverrsa-public.pem - Send this to SportradarNever expose your private key (rsa-private.pem) in client-side code, version control, or logs. Store it securely using environment variables or a secrets management system.
Never generate or sign JWT tokens in client-side JavaScript. Always create tokens on your backend to keep your private key secure.
Next action: Send the rsa-public.pem file to your Sportradar sales or client setup representative. They will configure the system to validate tokens signed with your private key.
Every logged-in user requires their own unique JWT. You have two implementation options:
All JWT tokens must include these standard claims:
{
sub: '<id>',
scope: 'av' | 'vs' | 'sb' | 'av vs sb',
iat: 1681718850
}Claim Descriptions:
| Claim | Type | Description | Example |
|---|---|---|---|
sub | string | Unique end-user identifier. Use your system's user ID or a salted hash if you prefer not to expose actual IDs. | 'user_12345' or 'a3f5b2c8d1e4' |
scope | string | Space-separated permissions for this user. Controls access to specific features.av - Enables audio/video stream access in Live Match Tracker.vs - Virtual Stadium access.sb - Bet Concierge access | 'av vs' for LMT audio/video and Virtual Stadium (space-separated) |
iat | number | Token issued-at timestamp in seconds since Unix epoch (UTC). Default validity: 16 hours. | 1681718850 |
The iat claim is typically added automatically by JWT libraries. You can also add an exp (expiration) claim to set a shorter validity period than the default 16 hours.
If implementing Virtual Stadium (scope vs), include these additional claims:
{
// Base claims (sub, scope, iat)
apiKey: '<key>',
userId: '<id>',
displayName: '<userName>',
userType: 'Normal' | 'VIP'
}| Claim | Type | Description | Example |
|---|---|---|---|
apiKey | string | Your Virtual Stadium API key (provided during onboarding) | 'vs_api_key_abc123' |
userId | string | Unique identifier for the user in Virtual Stadium | 'user_12345' |
displayName | string | Public name shown to other users in the Virtual Stadium interface | 'JohnDoe' or 'Player123' |
userType | string | User access level: 'Normal' or 'VIP'. VIP users have highlighted chat messages. | 'VIP' |
If implementing Bet Concierge (scope sb), include these additional claims:
{
// Base claims (sub, scope, iat)
// ... plus:
sbBrandId: '<id>',
sbUserType: '<type>'
}| Claim | Type | Description | Example |
|---|---|---|---|
sbBrandId | string | Your brand identifier (provided during onboarding) | 'brand_xyz789' |
sbUserType | string | Access level or category for the user in the bet concierge system. Can be any string value agreed upon with Sportradar during your client setup. This value is used for rate limiting and must be registered with your client setup configuration before issuing JWTs with it. Can be left empty if only a single user type is expected (e.g., in a development environment). | 'premium' or 'standard' |
Sign the JWT using your private key from Step 1. The signing algorithm must be RS256 (RSA Signature with SHA-256).
import jwt from "jsonwebtoken";
// Create token with base claims
const token = jwt.sign(
{
sub: "user_12345",
scope: "av vs", // Audio/video + Virtual Stadium
// iat is added automatically
},
process.env.PRIVATE_SIGNING_KEY,
{ algorithm: "RS256" },
);const vsToken = jwt.sign(
{
sub: "user_12345",
scope: "vs",
apiKey: process.env.VS_API_KEY,
userId: "user_12345",
displayName: "John Doe",
userType: "Normal",
},
process.env.PRIVATE_SIGNING_KEY,
{ algorithm: "RS256" },
);Deliver the signed JWT from your backend to your frontend application, then pass it to the widget during initialization.
Pass the JWT as a property when adding the widget using SIR:
SIR("addWidget", "#my-widget", "widget_name_here", {
jwt: generatedJwtToken,
// ... other widget properties
});<div id="lmt-widget"></div>
<script>
// Assume 'userJWT' is passed from your backend
const userJWT = "{{ jwt_from_backend }}";
// Initialize Live Match Tracker with JWT for audio/video
SIR("addWidget", "#lmt-widget", "sr-widgets-lmt", {
matchId: "sr:match:12345",
jwt: userJWT,
// ... other configuration
});
</script>If you need to rotate your private signing key, follow this process to rotate your JWT signing keys without service interruption: