How it works
User authenticates with your backend
Your application handles user login however you prefer — password, OAuth, SSO, or any other mechanism.
Your backend issues a signed JWT
After validating the user, your backend generates a JWT signed with the shared secret and returns it to the client over HTTPS.
Client passes the token to Red5 Pro
When the client connects to publish or subscribe, it includes the JWT as a connection parameter.
Prerequisites
Before configuring JWT Authentication, you need:- The
red5pro-simple-auth-plugininstalled on your Red5 Pro server (present by default) - A JWT-issuing service or identity provider
- A shared secret key of at least 32 bytes, used by both your issuing service and Red5 Pro
Step 1 — Configure the application
Add thejwtAuthenticator and simpleAuthSecurity beans to your application’s context file. For the live application, that file is RED5_HOME/webapps/live/WEB-INF/red5-web.xml. These beans are already present in the file but commented out — uncomment and adjust them.
Step 2 — Set properties
Add the following section toRED5_HOME/webapps/live/WEB-INF/red5-web.properties. The property values are substituted into red5-web.xml at runtime.
Configuration properties reference
Core (simpleAuthSecurity bean)| Property | Type | Description |
|---|---|---|
active | Boolean | Enables or disables authentication for the application |
rtmp | Boolean | Requires a valid JWT for RTMP connections |
rtsp | Boolean | Requires a valid JWT for RTSP connections |
rtc | Boolean | Requires a valid JWT for WebRTC connections |
srt | Boolean | Requires a valid JWT for SRT connections |
mpegts | Boolean | Requires a valid JWT for MPEG-TS connections |
rtmpAllowQueryParamsEnabled | Boolean | Allows RTMP clients to pass the token in the URL query string |
allowedRtmpAgents | String | Semicolon-separated list of allowed RTMP agent strings; * allows all |
| Property | Type | Description |
|---|---|---|
jwtSecret | String | Shared secret for validating JWT signatures |
jwtTtlMinutes | Long | Maximum allowed token lifetime in minutes; tokens with a longer exp are rejected |
expectedIssuer | String | Optional: if set, tokens must have a matching iss claim |
Step 3 — Generate tokens in your backend
Your backend service signs JWTs with the shared secret using the HS256 algorithm. Never generate tokens on the client side or embed the secret in client code.Token examples for common scenarios
Publisher-only token
Publisher-only token
Issue this to a broadcaster who should only be able to publish, not subscribe.
Subscriber-only token
Subscriber-only token
Issue this to a viewer who should only be able to subscribe, not publish.
Room-restricted token
Room-restricted token
Restrict the token to a specific room within the application scope.
Short-lived (near one-time) token
Short-lived (near one-time) token
Use a 60-second expiry for highly sensitive access scenarios.Set
jwt.ttl.minutes=2 on the server to tolerate up to 60 seconds of clock drift while still rejecting overly generous tokens.JWT claims reference
Standard claims
| Claim | Required | Description |
|---|---|---|
exp | Yes | Expiration timestamp (Unix seconds). Must be in the future and within jwtTtlMinutes. |
sub | Recommended | Subject (username). Stored as a connection attribute for logging and application use. |
iss | Conditional | Issuer. Required only if expectedIssuer is configured on the server. Case-sensitive. |
name | Optional | User’s full name. Stored as a connection attribute if present. |
Red5 Pro-specific claims
| Claim | Required | Description |
|---|---|---|
roles | Optional | Comma-separated roles. Recognized values: red5-publisher, red5-subscriber. If absent, both roles are allowed. |
red5-transport | Optional | Comma-separated allowed protocols: RTMP, RTSP, WHIP, WHEP. Case-insensitive. If absent, any protocol is allowed. |
red5-room | Optional | Comma-separated allowed room names (sub-scopes under the application). If absent, any room is allowed. |
For the stream path
live/room1/stream1, the room name is room1. If you
set red5-room, clients cannot access application-level streams that have
no room prefix.red5-publisher and red5-subscriber in lowercase. If your identity provider adds its own roles to the token (e.g., admin, editor), include the Red5 Pro roles alongside them:
Step 4 — Pass the token from your client
Clients send the JWT as thetoken parameter in their connection configuration. Set username and password to any non-empty value (conventionally "jwt").
- WebRTC (HTML5 SDK)
- RTMP (ActionScript)
- RTSP — Android
- RTSP — iOS
Pass the complete JWT string —
header.payload.signature — without a
Bearer prefix in the token parameter.Security best practices
Protect the shared secret
Protect the shared secret
Set appropriate token expiry
Set appropriate token expiry
Short-lived tokens limit the impact of token theft.
- Standard interactive sessions: 15–60 minutes
- High-security or near-one-time access: 60 seconds
- Configure
jwt.ttl.minutesslightly higher than your token TTL to tolerate clock drift between servers
Always use encrypted transport
Always use encrypted transport
- Send tokens from your backend to clients over HTTPS only
- Use RTMPS, RTSPS, or WebRTC (encrypted by default) for the streaming connection
- Never log or expose token strings in debug output or error messages
Enable issuer validation
Enable issuer validation
Set
jwt.issuer on the server to prevent tokens issued by other services from being accepted by Red5 Pro.When to use JWT Authentication
Good fits
- Production deployments with many users
- Microservices or API-gateway architectures that already issue JWTs
- Single Sign-On integrations (Auth0, Okta, AWS Cognito, Azure AD)
- Multi-tenant systems using room or issuer claims for isolation
- Applications requiring per-user role control (publisher vs. subscriber)
- Scenarios needing low-latency, stateless authentication
Poor fits
- Simple deployments with a small, fixed set of users — use Simple Authentication instead
- Situations with no JWT-issuing service available
- When you need real-time validation against live user state — use Round-Trip Authentication instead
