Security News
Node.js EOL Versions CVE Dubbed the "Worst CVE of the Year" by Security Experts
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
node-token-sockjs
Advanced tools
A wrapper around express, sockjs-node, and redis that provides token based authentication, a websocket based rpc-like abstraction, and an optional publish subscribe interface.
A wrapper around Express, Sockjs, and Redis that provides addtional websocket functionality.
This module is designed to support higher level application functionality on top of websockets or websocket emulation via sockjs. Currently this module provides a token-based authentication mechanism, a publish-subscribe interface, and a bidirectional RPC interface.
The client libraries can be found here.
npm install node-token-sockjs
This module supports the following initialization parameters. The first three named arguments are required and the last options object is optional.
var tokenServer = new TokenSocketServer(app, redisClient, socketServer, options);
The following properties are optional on the options object.
var express = require("express"),
http = require("http"),
redis = require("redis"),
sockjs = require("sockjs"),
TokenSocketServer = require("node-token-sockjs");
var redisClient = redis.createClient(),
pubsubClient = redis.createClient();
var app = express(),
socketServer = sockjs.createServer();
var server = http.createServer(app);
var socketOptions = {
prefix: "/sockets",
sockjs_url: "//cdn.sockjs.org/sockjs-0.3.min.js"
};
socketServer.installHandlers(server, socketOptions);
var authenticationFn = function(req, callback){
doSomething(req, function(error){
if(error)
return callback(error); // socket will not be allowed to connect
if(Math.random() < 0.5)
callback(null, req.user); // socket will be issued a token and req.user will be attached to the socket
else
callback(null, true); // socket will be issued a token and req.session will be attached to the socket
});
};
var readUsers = function(req, res){
console.log("Request to read users:", req.hostname, req.ip, req.headers, req.query, req.body);
User.read().then(function(users){
res.json(users);
})
.catch(function(error){
res.status(500);
res.json({ error: error });
});
};
app.get("/user/read", readUsers);
var controller = {
echo: function(auth, data, callback){
// here @auth is the second parameter from authenticationFn above, or req.session
// see the RPC section below for more information
callback(null, data);
}
};
// this will be attached to the HTTP route used to issue tokens to sockets
var customMiddleware = function(req, res, next){
req.foo = "bar";
next();
};
var tokenServer = new TokenSocketServer(app, redisClient, socketServer, {
prefix: socketOptions.prefix,
tokenRoute: "/socket/token",
pubsubClient: pubsubClient,
socketController: controller,
customMiddleware: customMiddleware,
authentication: authenticationFn,
debug: app.get("env") !== "production",
routes: {
user: {
read: readUsers // now this can be called via the RPC interface
}
},
ping: true
});
This module supports a bidirectional RPC interface between the server and client. This means the client can issue calls to the server and the server can issue calls to the client with a simple function call/callback interface. The examples here will show how to use the RPC API surface from the server. See the client docs for examples of RPC functions going in the other direction.
This example shows how to dynamically modify the socketController after the server has been initialized.
tokenServer.socketController.ping = function(auth, data, callback, socket){
// @auth is the data attached to the socket upon authentication
// @data is the data provided by the client when issuing the RPC call
// @callback is a function used to issue the final response to the client
// @socket is an optional parameter that can be used to issue inner RPC calls, pub/sub operations, etc.
doSomethingAsync(data, function(error, result){
if(error)
callback(error);
else
callback(null, result);
});
};
// call an RPC function on the client
var sockets = tokenServer.sockets();
var socket = sockets[Math.random() * (sockets.length - 1) | 0];
tokenServer.rpc(socket, "saySomething", { foo: "bar" }, function(error, resp){
console.log("Socket responded: ", error, resp);
});
The server is extended by an EventEmitter so developers can attach multiple event listeners to any event. Event listeners related to publish - subscribe actions (subscribe, publish, unsubscribe, broadcast) can be used to enforce access control to certain actions. See below for examples.
If multiple listener functions are bound to the same event only one of them needs to return an error or falsy value for the action to be disallowed.
tokenServer.on("authentication", function(socket, auth, callback){
// maybe immediately say hello
tokenServer.rpc(socket, "sayHello", { message: "hello, " + auth.email }, function(error, resp){
console.log("Socket client says: ", error, resp);
callback(); // the authentication event listener callback does not require any arguments
});
});
// enforce access control on publish - subscribe events
tokenServer.on("subscribe", function(socket, data, callback){
console.log("Socket attempting to subscribe: ", socket.auth, data.channel);
callback(null, true); // socket will be allowed to subscribe
});
tokenServer.on("publish", function(socket, data, callback){
console.log("Socket attempting to publish: ", socket.auth, data.channel, data.data);
callback(null, false); // socket will not be allowed to publish
});
// in this example the broadcast action will be disallowed
tokenServer.on("broadcast", function(socket, data, callback){
console.log("Socket attempting to broadcast: ", socket.auth, data.data);
callback(null, true);
});
tokenServer.on("broadcast", function(socket, data, callback){
console.log("Socket attempting to broadcast: ", socket.auth, data.data);
callback(null, false);
});
// listener functions can be removed with removeListener and removeAllListeners
tokenServer.removeAllListeners("authentication");
Sockjs does not support cookie based authentication nor the passing of query parameters on a websocket HTTP upgrade request so it is not possible to entirely disallow a websocket connection. However, it is possible to force sockets to authenticate before they're allowed to do anything. If a socket does not identify itself within a certain amount of time it can be forced to disconnect. This module allows for setting a TTL on unauthenticated sockets in this manner.
// set a 5 second TTL
tokenServer.enableCleanup(5000);
// remove the TTL
tokenServer.disableCleanup();
var sockets = tokenServer.sockets();
sockets.forEach(function(socket){
console.log("Socket ID: ", socket.sid);
console.log("Socket's channels: ", socket.channels);
console.log("Socket's auth data: ", socket.auth);
});
Developers can also use the optional publish/subscribe interface by providing an additional redis client to the module's initialization parameters.
TokenSocket clients can issue commands to subscribe themselves to channels or publish messages on a channel, however it is also possible for the server to perform pub/sub commands.
Publishes a message on a channel.
tokenServer.publish("channel", { foo: "bar" });
Broadcasts a message on all channels. If this is running in a distributed environment with a shared redis host this will broadcast the message on all channels, not just the channels that sockets connected to this server instance are subscribed to.
tokenServer.broadcast({ foo: "bar" });
var sockets = tokenServer.sockets();
sockets.forEach(function(socket){
tokenServer.subscribe(socket, "channel");
});
var sockets = tokenServer.sockets();
sockets.forEach(function(socket){
tokenServer.unsubscribe(socket, "channel");
});
// or unsubscribe all sockets from a channel
tokenServer.unsubscribeAll("channel");
var channel = "foo";
var sockets = tokenSocket.channelSockets(channel);
console.log("Channel " + channel + " has " + sockets.length + " sockets connected.");
By adding an optional synchronous function to the "filter" property on the socket server's initialization options developers can filter messages on the pub/sub network before the messages are sent to the clients. This function will be called with the socket, channel, and message as arguments. The return value of this function will be sent to the websocket client, however if the return value is falsy the server will not send the message to the client.
var tokenServer = new TokenSocketServer(app, redisClient, socketServer, {
pubsubClient: pubsubClient,
// ...
filter: function(socket, channel, message){
if(socket.auth.email === "foo")
delete message.bar;
return message;
}
});
List the channels that sockets connected to this server instance have subscribed to.
var channels = tokenServer.channels();
channels.forEach(function(channel){
tokenServer.publish(channel, { foo: "bar" });
});
Shut down the server by closing all sockets and unsubscribing from all channels. This is synchronous.
tokenServer.shutdown();
This module uses Mocha, Chai, and Sinon for testing. In order to run the tests make sure a local redis server is running on port 6379 or the REDIS_HOST and REDIS_PORT environment variables are set.
npm install
grunt
FAQs
A wrapper around express, sockjs-node, and redis that provides token based authentication, a websocket based rpc-like abstraction, and an optional publish subscribe interface.
The npm package node-token-sockjs receives a total of 17 weekly downloads. As such, node-token-sockjs popularity was classified as not popular.
We found that node-token-sockjs demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.