Cloud Messaging Security

  • Updated: Oct 17, 2016
  • Starting Guide

Securing a Realtime Messaging application is achieved through user authentication. The main authentication goal is preventing unauthorized use of established connections.

Failing to secure the ability to listen and write to subscribed channels of a connection not only compromises privacy but also opens way to tampering with messages making applications perform unwanted actions and consume incorrect data.

A Realtime Messaging subscription includes an application key (you can think of it as a public key) and a private key that uniquely identifies your website before the Realtime Messaging Server. Obviously this private key should only be used in server-side code. With these keys you can begin thinking about how you’re going to add trustworthy real-time capability to your website. This procedure requires that users’ be given an authentication token prior to a connection request to the Realtime Messaging servers. An authentication token is simply a string representing the user (e.g. a unique session id) or the group it belongs to (e.g. RegisteredUsers).

Activating authentication

For simplicity all Realtime subscriptions have authentication disabled by default. To use the security features described in this guide you need to activate authentication for your Realtime Messaging subscription.

You do that by editing your Realtime Messaging subscription in the Reatime Account Management website and turning the "Authentication" button to the "ON" position as shown below.

Don't forget to click the button SAVE at the bottom of the page so your changes become effective.

Now all your connections to Realtime need to be authenticated prior to connect. Attempting to connect with a non-authenticated token will result in an Invalid connection exception.

The authentication process

We’ll begin by giving an overview of the Realtime® authentication process and proceed to give examples of how to implement it.

This image, describing the authentication process, depicts a user interacting in a website with real-time capabilities. Initially, this website gathers the users’ credentials, anonymous or identified by a username and password and requests the authentication server (your web server) authorization to use the application and establish a real-time connection.

The authentication server, based on these credentials, generates an authentication token and a set of permissions that include the channels the user is allowed to use and their specific read/write (subscribe/publish) access. Next, it sends this information to the Realtime Messaging Server over a secure connection.

Upon receiving the batch of the users’ information, the Realtime Messaging Server stores this information and after successfully performing this operation notifies your web server which in turn returns the authentication token to the user as a response to the initial request (e.g. adding it to the server-side rendered html).

After that, the user issues a request to connect, directly to the Realtime Messaging Server, using the authentication token as means of identification. The server performs the necessary validations and replies with information related to the connection. The user can then publish/subscribe to the channels and start sending and receiving messages according to each channel permission (defined by for the user authentication token).

An example using PHP

Below is an example on posting the user authentication details from your PHP server to a Realtime Messaging server:

<?php
	require('./ortc.php');

	// Generate a random string to use as token
	function generateRandomString($length = 10) {
	    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	    $charactersLength = strlen($characters);
	    $randomString = '';
	    for ($i = 0; $i < $length; $i++) {
	        $randomString .= $characters[rand(0, $charactersLength - 1)];
	    }
	    return $randomString;
	}

	$URL = 'https://ortc-developers.realtime.co/server/ssl/2.1';
	$AK = 'ENTER-YOUR-REALTIME-APPKEY';
	$PK = 'ENTER-YOUR-REALTIME-PRIVATE-KEY';
	
	// Get a random string to use as Realtime token
	$TK = generateRandomString();
	
	$CH = 'myChannel';
	 
	// mocking the user login credentials only for demo
	// username: demo
	// password: demo
	$_USERPASS['demo'] = 'demo';

	// get the POST request with the user credentials
	$entityBody = file_get_contents('php://input');
	$json_o = json_decode($entityBody, true);

	// validate the credentials
	if ((isset($json_o['user']) == true) && (isset($json_o['pass'])) && in_array($json_o['user'], $_USERPASS) && strcmp($json_o['pass'], $_USERPASS[$json_o['user']]) == 0)  {
		// we have valid credentials
	    $rt = new Realtime( $URL, $AK, $PK, $TK );
	    $ttl = 180000;

	    // authenticate the token for the user
	    // giving write permissions for channel myChannel

	    $result = $rt->auth(
	        array(
	            $CH => 'w'
	        ),
	        0,
	        $ttl
	    );

	    if ($result == 1){
	    	// authenticated, return the generated token
	    	echo "{\"status\":\"success\",\"token\":\"".$TK."\"}";
	    }elseif ($result == 0) {
	    	// error authenticating the token
	    	echo "{\"status\":\"error\"}";
	    }
	}else{
		// invalid credentials
		echo "{\"status\":\"error\"}";
	}
?>
     

In the client side you could use jQuery ajax method to invoke the previous PHP script when the user logs in to your website.

The returned result will be the authenticated token to connect the user to Realtime:

var url = "/phpAuthServer/index.php"

function doAuthenticate(){
	var userField = document.getElementById("user");
	var passField = document.getElementById("pass");

	// validate login and get the authenticated token

	authenticate({user:userField.value, pass:passField.value}, url, function(data) {
		data = JSON.parse(data);

		if (data.status === "success") {
			// login was successful
			// save the authenticated token in the browser local storage
			localStorage.setItem("token", data.token);

			// redirect the user to the chat page
			window.location = "Realtime/index.html"
		}else if (data.status === "error") {
			// Oooops, something went wrong
			// Show an error message
			var errorLabel = document.getElementById("errorLabel");
			errorLabel.style.display = "block";
			localStorage.removeItem("token");
		};
	});
}

function authenticate(jsonData, url, callBack) {
	// invoke the PHP endpoint to validate the login and 
	// authenticate the Realtime token
	$.ajax({
	    url: url,
	    type: 'POST',
	    data:JSON.stringify(jsonData),
	    success: function(data) { 
	    	callBack(data);
	    },error: function(error) { 
	    	console.log(error);
	    }
	});
}
     

Click here to see the full PHP auth example code in GitHub.

If your server is not PHP you can use any other Realtime server SDK to perform the same actions (e.g. .NET, Java, Ruby and others)

Limitations

Number of authenticated channels per token

You are limited to 100 authenticated channels per user token.

If your use case needs more channels per user consider using sub-channels and authenticate the token using the wildcard *

Sub-channels are regular Realtime channels with the format

     		<main-channel>:<sub-channel>
     	

and you can use the format <main-channel>:* to authenticate the user token for all sub-channels of the main channel (the permissions set defined will be applied to all sub-channels and will count as only one channel towards the user token limit).

Adding channels to an already authenticated token

Every time a token is authenticated the previous permissions defined for that token are deleted. This means that if you want to add (or remove) a channel permission from an already authenticated token, you need to authenticate it again setting all the channel permissions, not simply the added channels.

Updating permissions of a token in use

Once the client is connected using an authenticated token, it will use the token permissions defined at the time of the connection. Even if the token expires or the permissions are updated after the connection .

In order to force a client to use the most recent token permissions you'll need to reconnect it (disconnect/connect).

Using TLS for extra security

Increased security can be achieved through the use of an TLS encrypted connection between the client and the Realtime Messaging Server.

To use this type of connection just replace the path /server/2.1 with /server/ssl/2.1 in your Realtime Messaging Cluster URL as shown below:

https://ortc-developers.realtime.co/server/ssl/2.1

Also if you want to grant permission for an authentication token to access the presence data of a given channel you should add the Presence permission for that specific channel (to know more about the Presence features please refer to the Presence documentation).

Other examples can be found in the SDK reference documentation at https://framework.realtime.co/messaging/#documentation.

Back to Overview - Next: Subscription filters

If you find this interesting please share: