Authenticate socket.io incoming connections with JWTs. This is useful if you are build a single page application and you are not using cookies as explained in this blog post: Cookies vs Tokens. Getting auth right with Angular.JS.
Installation
npm install socketio-jwt
Example usage
io.sockets
.on('connection', socketioJwt.authorize({
secret: 'your secret or public key',
timeout: 15000
})).on('authenticated', function(socket) {
console.log('hello! ' + socket.decoded_token.name);
});
Note: If you are using a base64-encoded secret (e.g. your Auth0 secret key), you need to convert it to a Buffer: Buffer('your secret key', 'base64')
Client side:
var socket = io.connect('http://localhost:9000');
socket.on('connect', function (socket) {
socket
.on('authenticated', function () {
})
.emit('authenticate', {token: jwt});
});
One roundtrip
The previous approach uses a second roundtrip to send the jwt, there is a way you can authenticate on the handshake by sending the JWT as a query string, the caveat is that intermediary HTTP servers can log the url.
var io = require("socket.io")(server);
var socketioJwt = require("socketio-jwt");
io.set('authorization', socketioJwt.authorize({
secret: 'your secret or public key',
handshake: true
}));
io.use(socketioJwt.authorize({
secret: 'your secret or public key',
handshake: true
}));
io.on('connection', function (socket) {
console.log('hello!', socket.handshake.decoded_token.name);
console.log('hello! ', socket.decoded_token.name);
})
For more validation options see auth0/jsonwebtoken.
Client side:
Append the jwt token using query string:
var socket = io.connect('http://localhost:9000', {
'query': 'token=' + your_jwt
});
Handling token expiration
Server side:
When you sign the token with an expiration time:
var token = jwt.sign(user_profile, jwt_secret, {expiresInMinutes: 60});
Your client-side code should handle it as below.
Client side:
socket.on("error", function(error) {
if (error.type == "UnauthorizedError" || error.code == "invalid_token") {
console.log("User's token has expired");
}
});
Getting the secret dynamically
You can pass a function instead of an string when configuring secret.
This function receives the request, the decoded token and a callback. This
way, you are allowed to use a different secret based on the request and / or
the provided token.
Server side:
var SECRETS = {
'user1': 'secret 1',
'user2': 'secret 2'
}
io.use(socketioJwt.authorize({
secret: function(request, decodedToken, callback) {
callback(null, SECRETS[decodedToken.userId]);
},
handshake: false
}));
Contribute
You are always welcome to open an issue or provide a pull-request!
Also check out the unit tests:
npm test
Issue Reporting
If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues.
Author
Auth0
License
This project is licensed under the MIT license. See the LICENSE file for more info.