Generate Authorization Token Server Side
LiveSwitch doesn't advise creating registration tokens in your client applications. This topic describes how to securely generate authorization tokens server side.
Why Not Generate Tokens Client Side?
LiveSwitch validates an authorization request if the token parameters are valid values and the secret key in the token matches the secret key configured on the LiveSwitch Gateway. If the client knows the secret key, then almost any request they make is valid. There is no way for your application to stop a client from registering or joining a channel.
The security of your app depends on keeping the secret key a secret. For each token that you want to generate, there are two types of data: things the client knows and things the server knows. Apply this concept to the following parameters required to generate authorization token:
- Application ID: A unique identifier for an application that comes from a server. It can be hard-coded or, more commonly, the ID might depend on a user's profile. Applications are associated with specific feature sets, so you don't want to allow the user to specify this ID as it can allow them to access features that they're not entitled to.
- User ID: A value that usually comes from a server. Before the server assigns an authorization token, it generally requires authentication from a user. You don't want to allow a client to specify this value, because the server already knows what the value should be and because it may allow a client to impersonate another user.
- Device ID: A value that usually comes from a client. A Device ID is a unique identifier associated with a particular device. This ID is used if a user is connected on multiple devices.
- Roles: Roles generally come from both a client and server. If an application role is associated with a specific application privilege, like moderation abilities, then the role is assigned by the server based on a user's profile. If a role isn't associated with any privileged action, like a presenter in a conference, then the client should request this role. The server should validate all client roles based on their user profile.
- Channel Claims: Channel claims usually come from a client. An example of a claim might be that the client has the right to join the specified channel. A server might also add other channels as required, if there are default channels or specific metadata channels associated with an application.
- Shared Secret: This arbitrary string comes from a server.
Generate Token Using LiveSwitch SDK
Set Up Your Server
To set up your authentication server, you need to set up a few things first. If you already have a server to handle application-specific data such as user profiles, that's a good starting point for your authentication server. The application server already has access to your user data which authorizes your client requests.
Set up at least two additional endpoints on your server:
- One that generates registration tokens
- One that generates channel tokens
This document assumes a REST-like API, and refers to these endpoints as /token/register
to register with the server and /token/join
to join a channel. In the following sections, some examples of server endpoints are provided using ASP .NET Core for C# and Spring 4 for Java.
Handle Registration Tokens
Authentication servers authenticate clients and return registration tokens so that clients can connect to the LiveSwitch service. Registration tokens are typically generated from a /token/register
endpoint on a REST-ful web service. In a normal registration request, the Application ID, user ID, and shared secret are provided by the server. The only remaining parameters required are the device ID and the client ID, because roles and channel claims are optional for a registration.
The following code snippet shows platform-specific examples of retrieving device and client IDs and then making an HTTP request to the server for a registration token. The device ID and client ID are provided through query parameters in a POST request.
var applicationId = "...";
var userId = "...";
var deviceId = Environment.MachineName;
var client = new FM.LiveSwitch.Client("https://liveswitch.server:8443/sync", applicationId, userId, deviceId);
var url = "https://app.server/token/register"
+ "?deviceId=" + client.DeviceId
+ "&clientId=" + client.Id;
var httpClient = new HttpClient();
var response = await httpClient.PostAsync(url);
var token = response.Content;
client.Register(token).Then(...);
You have to configure your application server to receive this request. The application server should then respond by generating a client registration token. You can generate this token using the values the client provides, and values available to the server. Pass all these values to the GenerateClientRegisterToken
static method of the FM.LiveSwitch.Token
class to return a token. This is demonstrated below.
[Route("[controller]")]
public class TokenController : Controller
{
private String secret;
private UserManager<AppUser> userManager;
public TokenController(UserManager<AppUser> userManager)
{
this.userManager = userManager;
}
[HttpPost("register")]
public ContentResult Register([FromQuery]string deviceId, [FromQuery]string clientId)
{
var user = await this.userManager.GetUserAsync(this.User);
return Content(FM.LiveSwitch.Token.GenerateClientRegisterToken(
user.ApplicationId,
user.Id,
deviceId,
null,
null,
null
this.secret
));
}
}
The details of how these controllers' shared secret property is provided is up to you. A common way of doing this is through your dependency injection container. You can also query your global application settings. Whatever way you select, it shouldn't be accessible to any clients.
Handle Channel Tokens
Authentication servers return channel tokens so that registered users can join additional channels without re-registering. Channel tokens are usually generated from a /token/join
endpoint on a REST-ful web service.
For a join token, the client must provide its deviceId
and clientId
again. It must also provide the ID of a channel it wishes to join. The code samples below show how to make a REST-ful request with this information embedded in the query string.
var applicationId = "...";
var userId = "...";
var channelId = "...";
var deviceId = Environment.MachineName;
var client = new FM.LiveSwitch.Client("https://liveswitch.server:8443/sync", applicationId, userId, deviceId);
var url = "https://app.server/token/join"
+ "?deviceId=" + client.DeviceId
+ "&channelId=" + channelId;
var httpClient = new HttpClient();
var response = await httpClient.PostAsync(url);
string token = response.Content;
client.Join(channelId, token).Then(...);
You must configure a /token/join
endpoint to receive this request. The endpoint should respond with a join token that allows the client to join their requested channel. You generate this token using the GenerateClientJoinToken
static method of the FM.LiveSwitch.Token
class. Note that you must wrap the channel ID provided by the client in an instance of FM.LiveSwitch.ChannelClaim
.
[Route("[controller]")]
public class TokenController : Controller
{
private String secret;
private UserManager<AppUser> userManager;
public TokenController(UserManager<AppUser> userManager)
{
this.userManager = userManager;
}
[HttpPost("join")]
public ContentResult Join([FromQuery]string deviceId, [FromQuery]string clientId, [FromQuery]string channelId)
{
var user = await this.userManager.GetUserAsync(this.User);
return Content(FM.LiveSwitch.Token.GenerateClientJoinToken(
user.ApplicationId,
user.Id,
deviceId,
null,
new FM.LiveSwitch.ChannelClaim(channelId),
this.secret
));
}
}
Generate Token Using Third-Party Service
You can use a third-party service for authentication, such as Auth0.
You can also use a JWT library such as PHP-JWT to generate the tokens, as shown in the example code below.
Register Token
var secret = '...';
var token = jwt.sign({
type: 'register',
applicationId: '...',
userId: '...',
deviceId: '...',
channels: [{ // optional, any count
id: '...'
}],
clientRoles: ['...'], // optional, any count
region: '...' // optional
}, secret, {
algorithm: 'HS256',
expiresIn: 300 // seconds
});
Join Token
var secret = '...';
var token = jwt.sign({
type: 'join',
applicationId: '...',
userId: '...',
deviceId: '...',
clientId: '...',
channels: [{ // exactly 1 required
id: '...'
}]
}, secret, {
algorithm: 'HS256',
expiresIn: 300 // seconds
});
Note
LiveSwitch only supports the HS256 algorithm.