Step by step instruction of setting up real-time secure broadcasting with Laravel 5.1, and redis


A few weeks ago I was struggling with setting up real time broadcasting with Laravel and The biggest problem was security issue. So now I would like to show my solution of this problem. If you have any comments or want to suggest a more efficient way of solving this problem - please share. So let's get started.

Technology stack used in this example : Laravel 5.1, Angular 1.4, Redis, NodeJS,, JWT.


I was using REST API and JWT auth in my app. So first thing to do is to set up config and JWT token in config controller.

 composer require tymon/jwt-auth 

Add provider :


and aliases :

'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class

And finally run this command to generate jwt config:

php artisan jwt:generate 

use Illuminate\Contracts\Auth\Guard;
use Tymon\JWTAuth\JWTAuth;
use Carbon\Carbon;
class CfgController extends Controller
protected $JWTAuth;
protected $auth;
  public function __construct(JWTAuth $JWTAuth, Guard $auth)
    $this->JWTAuth = $JWTAuth;
    $this->auth = $auth;
public function index()
    $user = $this->auth->user();
    $tokenId    = base64_encode(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
    $issuedAt   = Carbon::now()->timestamp;
    $notBefore  = $issuedAt;             //Adding 10 seconds
    $expire     = $notBefore + 6*60*60;            // Adding 6 hours
    * Create the token as an array
    $data = [
      'iat'  => $issuedAt,      // Issued at: time when the token was generated
      'jti'  => $tokenId,   // Json Token Id: an unique identifier for the token
      'iss'  => '',       // Issuer
      'nbf'  => $notBefore,        // Not before
      'exp'  => $expire,           // Expire
      'data' => [                  // Data related to the signed user
        'userId'   => \Auth::id(), // userid from the users table
  $response = [
        'jwt'           => $this->JWTAuth->fromUser($user, $data),
        'node_url'      => '', //better to move this to .env file
  return response()->json($response);

Now you can set up route for this action in routes.php file.

For example:

Route::get('/cfg', 'CfgController@index');  

Also we should add Laravel event to perform broadcasting.


class NewMessage extends Event implements ShouldBroadcast
  use SerializesModels;
  public $user;
  public $message;
  private $recipientsIds;
  public function __construct($message, array $recipients)
    $ids = [];
    foreach($recipients as $recipient) {
      $ids[] = $recipient['user']['id'];
    $this->message = $message;
    $this->recipientsIds = $ids;
  public function broadcastOn()
    $events = [];
    foreach($this->recipientsIds as $res) {
      $events[] = 'user.' . $res;
    return $events;
  public function broadcastWith()
    return ['message' => $this->message]; 
    //this is not necessary. All public properties are automatically broadcast


You can reference config url in your angular application.

For example: template.blade.php

    element: document.documentElement,
    module: 'app',
    resolve: {
      APP_CONFIG: ['$http', '$q', function ($http, $q) {
        var deferred = $q.defer();
        // GET api cfg token
        $http.get('/cfg', {withCredentials: true}).success(function(resp){
        return deferred.promise;

To use deferred bootstrap you should install "angular-deferred-bootstrap" package.

Now, you can use APP_CONFIG in your controllers. 

In my case I use it to store JWT token. In your angular controller or service you should subscribe to events. Example:

function RealTimeService(APP_CONFIG){
  var socket = io(APP_CONFIG.node_url, {secure: true, query: 'jwt=' + APP_CONFIG.jwt});
  socket.on('App\\Events\\NewMessage', function(data) {
    //here you can persist all your data passed in NewMessage event

Pay attention to this code:

 query: 'jwt=' + APP_CONFIG.jwt 

We will use this jwt token on nodeJS server to get user id.

And now the most important part of application. + nodeJS server 

First install needed dependencies via npm:

ioredis, jsonwebtoken, node-env-file, 

Of course, Redis server should be installed and running. 

Also you can add to your .env file SOCKETIO_PORT, JWT_SECRET, REDIS_DB and ssl certificate urls if needed. Or simply hardcode in your js file. Example of server.js:

var ENV = require('node-env-file')(__dirname + '/../.env');
var fs = require('fs');
var Redis = require('ioredis');
var redis = new Redis({
  db: ENV.REDIS_DB || 0
var jwt = require('jsonwebtoken');
//I’m using ssl, but this is not a must
var ssl_conf = {
  ca: (ENV.SOCKETIO_SSL_CA_FILE ? [fs.readFileSync(ENV.SOCKETIO_SSL_CA_FILE1), fs.readFileSync(ENV.SOCKETIO_SSL_CA_FILE2)] : null)
var app = require('https').createServer(ssl_conf, handler);
var io = require('').listen(app);
var cookie = require('cookie');
function handler(req, res) {
io.use(function(socket, next) {
  var decoded;
  try {
    decoded = jwt.verify(socket.handshake.query.jwt, ENV.JWT_SECRET);
  } catch (err) {
    next(new Error('Invalid token!'));
  if (decoded) {
    // everything went fine - save userId as property of given connection instance
    socket.userId =; // save user id we just got from the token, to be used later
  } else {
    // invalid token - terminate the connection
    next(new Error('Invalid token!'));
io.on('connection', function(socket) {
  socket.join('user.' + socket.userId);
redis.psubscribe('*', function(err, count) {
redis.on('pmessage', function(subscribed, channel, message) {
  message = JSON.parse(message);,;
console.log('Starting on port : '+ENV.SOCKETIO_PORT);

So, now when user is connecting to channel we are parsing its JWT and setting userId to socket.

After that, we are connecting user to his own room using socket.join(…)

And emitting this data to the client. 

Using this approach, data is securely hidden from other clients. Also, if you are not using JWT for your authorization you can grab userId from cookie. But pay attention to your nodeJS server. It should run on the same domain as your app.

Step by step instruction of setting up real-time secure broadcasting with Laravel 5.1, and redis