Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

socketio-jwt

Package Overview
Dependencies
Maintainers
2
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

socketio-jwt - npm Package Compare versions

Comparing version 4.5.0 to 4.5.1

.all-contributorsrc

199

lib/index.js

@@ -1,15 +0,16 @@

var xtend = require('xtend');
var jwt = require('jsonwebtoken');
var UnauthorizedError = require('./UnauthorizedError');
const xtend = require('xtend');
const jwt = require('jsonwebtoken');
const UnauthorizedError = require('./UnauthorizedError');
function noQsMethod(options) {
var defaults = { required: true };
options = xtend(defaults, options);
function noQsMethod (options) {
const defaults = { required: true };
options = xtend(defaults, options);
return function (socket) {
var server = this.server || socket.server;
return (socket) => {
'use strict'; // Node 4.x workaround
const server = this.server || socket.server;
if (!server.$emit) {
//then is socket.io 1.0
var Namespace = Object.getPrototypeOf(server.sockets).constructor;
const Namespace = Object.getPrototypeOf(server.sockets).constructor;
if (!~Namespace.events.indexOf('authenticated')) {

@@ -20,4 +21,5 @@ Namespace.events.push('authenticated');

if(options.required){
var auth_timeout = setTimeout(function () {
let auth_timeout = null;
if (options.required) {
auth_timeout = setTimeout(() => {
socket.disconnect('unauthorized');

@@ -27,42 +29,50 @@ }, options.timeout || 5000);

socket.on('authenticate', function (data) {
if(options.required){
socket.on('authenticate', (data) => {
if (options.required) {
clearTimeout(auth_timeout);
}
// error handler
var onError = function(err, code) {
if (err) {
code = code || 'unknown';
var error = new UnauthorizedError(code, {
message: (Object.prototype.toString.call(err) === '[object Object]' && err.message) ? err.message : err
});
var callback_timeout;
// If callback explicitely set to false, start timeout to disconnect socket
if (options.callback === false || typeof options.callback === "number") {
if (typeof options.callback === "number") {
if (options.callback < 0) {
// If callback is negative(invalid value), make it positive
options.callback = Math.abs(options.callback);
}
const onError = (err, code) => {
if (err) {
code = code || 'unknown';
const error = new UnauthorizedError(code, {
message: (Object.prototype.toString.call(err) === '[object Object]' && err.message) ? err.message : err
});
let callback_timeout;
// If callback explicitly set to false, start timeout to disconnect socket
if (options.callback === false || typeof options.callback === 'number') {
if (typeof options.callback === 'number') {
if (options.callback < 0) {
// If callback is negative(invalid value), make it positive
options.callback = Math.abs(options.callback);
}
callback_timeout = setTimeout(function () {
socket.disconnect('unauthorized');
}, (options.callback === false ? 0 : options.callback));
}
socket.emit('unauthorized', error, function() {
if (typeof options.callback === "number") {
clearTimeout(callback_timeout);
}
callback_timeout = setTimeout(() => {
socket.disconnect('unauthorized');
});
return; // stop logic, socket will be close on next tick
}, (options.callback === false ? 0 : options.callback));
}
socket.emit('unauthorized', error, () => {
if (typeof options.callback === 'number') {
clearTimeout(callback_timeout);
}
socket.disconnect('unauthorized');
});
return; // stop logic, socket will be close on next tick
}
};
if(!data || typeof data.token !== "string") {
return onError({message: 'invalid token datatype'}, 'invalid_token');
const token = options.cookie ? socket.request.cookies[options.cookie] : (data ? data.token : undefined);
if (!token || typeof token !== 'string') {
return onError({ message: 'invalid token datatype' }, 'invalid_token');
}
var onJwtVerificationReady = function(err, decoded) {
// Store encoded JWT
socket[options.encodedPropertyName] = token;
const onJwtVerificationReady = (err, decoded) => {
if (err) {

@@ -73,4 +83,6 @@ return onError(err, 'invalid_token');

// success handler
var onSuccess = function() {
socket[options.decodedPropertyName] = decoded;
const onSuccess = () => {
socket[options.decodedPropertyName] = options.customDecoded
? options.customDecoded(decoded)
: decoded;
socket.emit('authenticated');

@@ -81,5 +93,5 @@ if (server.$emit) {

//try getting the current namespace otherwise fallback to all sockets.
var namespace = (server.nsps && socket.nsp &&
server.nsps[socket.nsp.name]) ||
server.sockets;
const namespace = (server.nsps && socket.nsp &&
server.nsps[socket.nsp.name]) ||
server.sockets;

@@ -91,3 +103,3 @@ // explicit namespace

if(options.additional_auth && typeof options.additional_auth === 'function') {
if (options.additional_auth && typeof options.additional_auth === 'function') {
options.additional_auth(decoded, onSuccess, onError);

@@ -99,3 +111,3 @@ } else {

var onSecretReady = function(err, secret) {
const onSecretReady = (err, secret) => {
if (err || !secret) {

@@ -105,6 +117,6 @@ return onError(err, 'invalid_secret');

jwt.verify(data.token, secret, options, onJwtVerificationReady);
jwt.verify(token, secret, options, onJwtVerificationReady);
};
getSecret(socket.request, options.secret, data.token, onSecretReady);
getSecret(socket.request, options.secret, token, onSecretReady);
});

@@ -114,5 +126,9 @@ };

function authorize(options, onConnection) {
options = xtend({ decodedPropertyName: 'decoded_token' }, options);
function authorize (options) {
options = xtend({ decodedPropertyName: 'decoded_token', encodedPropertyName: 'encoded_token' }, options);
if (typeof options.secret !== 'string' && typeof options.secret !== 'function') {
throw new Error(`Provided secret ${options.secret} is invalid, must be of type string or function.`);
}
if (!options.handshake) {

@@ -122,5 +138,5 @@ return noQsMethod(options);

var defaults = {
success: function(data, accept){
if (data.request) {
const defaults = {
success: (socket, accept) => {
if (socket.request) {
accept();

@@ -131,4 +147,4 @@ } else {

},
fail: function(error, data, accept){
if (data.request) {
fail: (error, socket, accept) => {
if (socket.request) {
accept(error);

@@ -141,14 +157,17 @@ } else {

var auth = xtend(defaults, options);
const auth = xtend(defaults, options);
return function(data, accept){
var token, error;
var req = data.request || data;
var authorization_header = (req.headers || {}).authorization;
return (socket, accept) => {
'use strict'; // Node 4.x workaround
let token, error;
const handshake = socket.handshake;
const req = socket.request || socket;
const authorization_header = (req.headers || {}).authorization;
if (authorization_header) {
var parts = authorization_header.split(' ');
const parts = authorization_header.split(' ');
if (parts.length == 2) {
var scheme = parts[0],
credentials = parts[1];
const scheme = parts[0],
credentials = parts[1];

@@ -162,8 +181,18 @@ if (scheme.toLowerCase() === 'bearer') {

});
return auth.fail(error, data, accept);
return auth.fail(error, socket, accept);
}
}
//get the token from query string
if (req._query && req._query.token) {
// Check if the header has to include authentication
if (options.auth_header_required && !token) {
return auth.fail(new UnauthorizedError('missing_authorization_header', {
message: 'Server requires Authorization Header'
}), socket, accept);
}
// Get the token from handshake or query string
if (handshake && handshake.query.token) {
token = handshake.query.token;
}
else if (req._query && req._query.token) {
token = req._query.token;

@@ -177,23 +206,27 @@ }

error = new UnauthorizedError('credentials_required', {
message: 'No Authorization header was found'
message: 'no token provided'
});
return auth.fail(error, data, accept);
return auth.fail(error, socket, accept);
}
var onJwtVerificationReady = function(err, decoded) {
// Store encoded JWT
socket[options.encodedPropertyName] = token;
const onJwtVerificationReady = (err, decoded) => {
if (err) {
error = new UnauthorizedError(err.code || 'invalid_token', err);
return auth.fail(error, data, accept);
return auth.fail(error, socket, accept);
}
data[options.decodedPropertyName] = decoded;
socket[options.decodedPropertyName] = options.customDecoded
? options.customDecoded(decoded)
: decoded;
return auth.success(data, accept);
return auth.success(socket, accept);
};
var onSecretReady = function(err, secret) {
const onSecretReady = (err, secret) => {
if (err) {
error = new UnauthorizedError(err.code || 'invalid_secret', err);
return auth.fail(error, data, accept);
return auth.fail(error, socket, accept);
}

@@ -208,3 +241,5 @@

function getSecret(request, secret, token, callback) {
function getSecret (request, secret, token, callback) {
'use strict'; // Node 4.x workaround
if (typeof secret === 'function') {

@@ -215,3 +250,3 @@ if (!token) {

var parts = token.split('.');
const parts = token.split('.');

@@ -226,3 +261,3 @@ if (parts.length < 3) {

var decodedToken = jwt.decode(token);
let decodedToken = jwt.decode(token, { complete: true });

@@ -233,8 +268,14 @@ if (!decodedToken) {

secret(request, decodedToken, callback);
const arity = secret.length;
if (arity == 4) {
secret(request, decodedToken.header, decodedToken.payload, callback);
} else { // arity == 3
secret(request, decodedToken.payload, callback);
}
} else {
callback(null, secret);
}
};
}
exports.authorize = authorize;
exports.UnauthorizedError = UnauthorizedError;

@@ -8,3 +8,3 @@ function UnauthorizedError (code, error) {

code: code,
type: "UnauthorizedError"
type: 'UnauthorizedError'
};

@@ -11,0 +11,0 @@ }

{
"name": "socketio-jwt",
"version": "4.5.0",
"version": "4.5.1",
"description": "authenticate socket.io connections using JWTs",
"main": "lib/index.js",
"types": "./types/index.d.ts",
"keywords": [

@@ -25,17 +26,18 @@ "socket",

"dependencies": {
"jsonwebtoken": "^5.0.0",
"jsonwebtoken": "^8.3.0",
"xtend": "~2.1.2"
},
"devDependencies": {
"body-parser": "~1.13.3",
"express": "~4.10.6",
"mocha": "~1.17.0",
"passport-local": "~0.1.6",
"request": "~2.19.0",
"serve-static": "^1.7.1",
"@types/socket.io": "~1.4.29",
"body-parser": "~1.17.1",
"express": "~4.15.2",
"mocha": "~3.2.0",
"request": "~2.81.0",
"serve-static": "^1.13.2",
"q": "^1.5.1",
"server-destroy": "~1.0.1",
"should": "~1.2.2",
"socket.io": "^1.0.4",
"socket.io-client": "^1.0.4"
"should": "~11.2.1",
"socket.io": "^1.7.3",
"socket.io-client": "^1.7.3"
}
}

@@ -1,12 +0,37 @@

[![Build Status](https://travis-ci.org/auth0/socketio-jwt.svg)](https://travis-ci.org/auth0/socketio-jwt)
# socketio-jwt
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](http://blog.auth0.com/2014/01/07/angularjs-authentication-with-cookies-vs-token/).
[![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors)
<img src="https://img.shields.io/badge/community-driven-brightgreen.svg"/> <br>
### Contributors
Thanks goes to these wonderful people who contribute(d) or maintain(ed) this repo ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore -->
<table>
<tr>
<td align="center"><a href="https://twitter.com/beardaway"><img src="https://avatars3.githubusercontent.com/u/11062800?v=4" width="100px;" alt="Conrad Sopala"/><br /><sub><b>Conrad Sopala</b></sub></a><br /><a href="#review-beardaway" title="Reviewed Pull Requests">👀</a> <a href="#maintenance-beardaway" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/Annyv2"><img src="https://avatars3.githubusercontent.com/u/5016479?v=4" width="100px;" alt="Annyv2"/><br /><sub><b>Annyv2</b></sub></a><br /><a href="https://github.com/auth0-community/auth0-socketio-jwt/commits?author=Annyv2" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Amialc"><img src="https://avatars0.githubusercontent.com/u/1114365?v=4" width="100px;" alt="Vladyslav Martynets"/><br /><sub><b>Vladyslav Martynets</b></sub></a><br /><a href="https://github.com/auth0-community/auth0-socketio-jwt/commits?author=Amialc" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/pose"><img src="https://avatars3.githubusercontent.com/u/419703?v=4" width="100px;" alt="Alberto Pose"/><br /><sub><b>Alberto Pose</b></sub></a><br /><a href="https://github.com/auth0-community/auth0-socketio-jwt/commits?author=pose" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Root-Core"><img src="https://avatars2.githubusercontent.com/u/5329652?v=4" width="100px;" alt="Root-Core"/><br /><sub><b>Root-Core</b></sub></a><br /><a href="https://github.com/auth0-community/auth0-socketio-jwt/commits?author=Root-Core" title="Code">💻</a></td>
</tr>
</table>
<!-- ALL-CONTRIBUTORS-LIST:END -->
## Intro
Authenticate socket.io incoming connections with JWTs. This is useful if you are building 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](http://blog.auth0.com/2014/01/07/angularjs-authentication-with-cookies-vs-token/).
This repo is supported and maintained by Community Developers, not Auth0. For more information about different support levels check https://auth0.com/docs/support/matrix .
## Installation
```
```bash
npm install socketio-jwt
```
## Example usage
## Usage

@@ -19,5 +44,6 @@ ```javascript

timeout: 15000 // 15 seconds to send the authentication message
})).on('authenticated', function(socket) {
}))
.on('authenticated', (socket) => {
//this socket is authenticated, we are good to handle more events from it.
console.log('hello! ' + socket.decoded_token.name);
console.log(`hello! ${socket.decoded_token.name}`);
});

@@ -28,24 +54,31 @@ ```

__Client side__:
**Client side**
```javascript
var socket = io.connect('http://localhost:9000');
socket.on('connect', function (socket) {
const socket = io.connect('http://localhost:9000');
socket.on('connect', () => {
socket
.on('authenticated', function () {
.emit('authenticate', { token: jwt }) //send the jwt
.on('authenticated', () => {
//do other things
})
.emit('authenticate', {token: jwt}); //send the jwt
.on('unauthorized', (msg) => {
console.log(`unauthorized: ${JSON.stringify(msg.data)}`);
throw new Error(msg.data.type);
})
});
```
## One roundtrip
### 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.
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.
```javascript
var io = require("socket.io")(server);
var socketioJwt = require("socketio-jwt");
const io = require('socket.io')(server);
const socketioJwt = require('socketio-jwt');
```
//// With socket.io < 1.0 ////
With socket.io < 1.0:
```javascript
io.set('authorization', socketioJwt.authorize({

@@ -55,5 +88,11 @@ secret: 'your secret or public key',

}));
//////////////////////////////
//// With socket.io >= 1.0 ////
io.on('connection', (socket) => {
console.log('hello!', socket.handshake.decoded_token.name);
});
```
With socket.io >= 1.0:
```javascript
io.use(socketioJwt.authorize({

@@ -63,11 +102,6 @@ secret: 'your secret or public key',

}));
///////////////////////////////
io.on('connection', function (socket) {
// in socket.io < 1.0
console.log('hello!', socket.handshake.decoded_token.name);
// in socket.io 1.0
console.log('hello! ', socket.decoded_token.name);
})
io.on('connection', (socket) => {
console.log('hello!', socket.decoded_token.name);
});
```

@@ -77,3 +111,3 @@

__Client side__:
**Client side**

@@ -83,26 +117,50 @@ Append the jwt token using query string:

```javascript
var socket = io.connect('http://localhost:9000', {
'query': 'token=' + your_jwt
const socket = io.connect('http://localhost:9000', {
query: `token=${your_jwt}`
});
```
## Handling token expiration
Append the jwt token using 'Authorization Header' (Bearer Token):
__Server side__:
```javascript
const socket = io.connect('http://localhost:9000', {
extraHeaders: { Authorization: `Bearer ${your_jwt}` }
});
```
When you sign the token with an expiration time:
Both options can be combined or used optionally.
### Authorization Header Requirement
Require Bearer Tokens to be passed in as an Authorization Header
**Server side**:
```javascript
var token = jwt.sign(user_profile, jwt_secret, {expiresInMinutes: 60});
io.use(socketioJwt.authorize({
secret: 'your secret or public key',
handshake: true,
auth_header_required: true
}));
```
Your client-side code should handle it as below.
### Handling token expiration
__Client side__:
**Server side**
When you sign the token with an expiration time (example: 60 minutes):
```javascript
socket.on("error", function(error) {
if (error.type == "UnauthorizedError" || error.code == "invalid_token") {
const token = jwt.sign(user_profile, jwt_secret, { expiresIn: 60*60 });
```
Your client-side code should handle it as below:
**Client side**
```javascript
socket.on('unauthorized', (error) => {
if (error.data.type == 'UnauthorizedError' || error.data.code == 'invalid_token') {
// redirect user to login page perhaps?
console.log("User's token has expired");
console.log('User token has expired');
}

@@ -112,11 +170,11 @@ });

## Handling invalid token
### Handling invalid token
Token sent by client is invalid.
__Server side__:
**Server side**:
No further configuration needed.
__Client side__:
**Client side**

@@ -126,7 +184,7 @@ Add a callback client-side to execute socket disconnect server-side.

```javascript
socket.on("unauthorized", function(error, callback) {
if (error.data.type == "UnauthorizedError" || error.data.code == "invalid_token") {
socket.on('unauthorized', (error, callback) => {
if (error.data.type == 'UnauthorizedError' || error.data.code == 'invalid_token') {
// redirect user to login page perhaps or execute callback:
callback();
console.log("User's token has expired");
console.log('User token has expired');
}

@@ -136,3 +194,3 @@ });

__Server side__:
**Server side**

@@ -145,11 +203,11 @@ To disconnect socket server-side without client-side callback:

// No client-side callback, terminate connection server-side
callback: false
callback: false
}))
```
__Client side__:
**Client side**
Nothing needs to be changed client-side if callback is false.
__Server side__:
**Server side**

@@ -162,16 +220,16 @@ To disconnect socket server-side while giving client-side 15 seconds to execute callback:

// Delay server-side socket disconnect to wait for client-side callback
callback: 15000
callback: 15000
}))
```
Your client-side code should handle it as below.
Your client-side code should handle it as below:
__Client side__:
**Client side**
```javascript
socket.on("unauthorized", function(error, callback) {
if (error.data.type == "UnauthorizedError" || error.data.code == "invalid_token") {
socket.on('unauthorized', (error, callback) => {
if (error.data.type == 'UnauthorizedError' || error.data.code == 'invalid_token') {
// redirect user to login page perhaps or execute callback:
callback();
console.log("User's token has expired");
console.log('User token has expired');
}

@@ -181,4 +239,5 @@ });

## Getting the secret dynamically
You can pass a function instead of an string when configuring secret.
### Getting the secret dynamically
You can pass a function instead of a string when configuring secret.
This function receives the request, the decoded token and a callback. This

@@ -188,6 +247,6 @@ way, you are allowed to use a different secret based on the request and / or

__Server side__:
**Server side**
```javascript
var SECRETS = {
const SECRETS = {
'user1': 'secret 1',

@@ -198,4 +257,4 @@ 'user2': 'secret 2'

io.use(socketioJwt.authorize({
secret: function(request, decodedToken, callback) {
// SECRETS[decodedToken.userId] will be used a a secret or
secret: (request, decodedToken, callback) => {
// SECRETS[decodedToken.userId] will be used as a secret or
// public key for connection user.

@@ -207,3 +266,25 @@

}));
```
### Altering the value of the decoded token
You can pass a function to change the value of the decoded token
```javascript
io.on(
'connection',
socketIOJwt.authorize({
customDecoded: (decoded) => {
return "new decoded token";
},
secret: 'my_secret_key',
decodedPropertyName: 'my_decoded_token',
}),
);
io.on('authenticated', (socket) => {
console.log(socket.my_decoded_token); // new decoded token
});
```

@@ -213,5 +294,7 @@

You are always welcome to open an issue or provide a pull-request!
Feel like contributing to this repo? We're glad to hear that! Before you start contributing please visit our [Contributing Guideline](https://github.com/auth0-community/getting-started/blob/master/CONTRIBUTION.md).
Also check out the unit tests:
Here you can also find the [PR template](https://github.com/auth0-community/socketio-jwt/blob/master/PULL_REQUEST_TEMPLATE.md) to fill once creating a PR. It will automatically appear once you open a pull request.
You might run the unit tests, before creating a PR:
```bash

@@ -221,12 +304,51 @@ npm test

## Issue Reporting
## Issues 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](https://auth0.com/whitehat) details the procedure for disclosing security issues.
Spotted a bug or any other kind of issue? We're just humans and we're always waiting for constructive feedback! Check our section on how to [report issues](https://github.com/auth0-community/getting-started/blob/master/CONTRIBUTION.md#issues)!
## Author
Here you can also find the [Issue template](https://github.com/auth0-community/socketio-jwt/blob/master/ISSUE_TEMPLATE.md) to fill once opening a new issue. It will automatically appear once you create an issue.
[Auth0](auth0.com)
## Repo Community
Feel like PRs and issues are not enough? Want to dive into further discussion about the tool? We created topics for each Auth0 Community repo so that you can join discussion on stack available on our repos. Here it is for this one: [socketio-jwt](https://community.auth0.com/t/auth0-community-oss-socketio-jwt/20024)
<a href="https://community.auth0.com/">
<img src="/assets/join_auth0_community_badge.png"/>
</a>
## License
This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info.
This project is licensed under the MIT license. See the [LICENSE](https://github.com/auth0-community/socketio-jwt/blob/master/LICENSE) file for more info.
## What is Auth0?
Auth0 helps you to:
* Add authentication with [multiple authentication sources](https://docs.auth0.com/identityproviders), either social like
* Google
* Facebook
* Microsoft
* Linkedin
* GitHub
* Twitter
* Box
* Salesforce
* etc.
**or** enterprise identity systems like:
* Windows Azure AD
* Google Apps
* Active Directory
* ADFS
* Any SAML Identity Provider
* Add authentication through more traditional [username/password databases](https://docs.auth0.com/mysql-connection-tutorial)
* Add support for [linking different user accounts](https://docs.auth0.com/link-accounts) with the same user
* Support for generating signed [JSON Web Tokens](https://docs.auth0.com/jwt) to call your APIs and create user identity flow securely
* Analytics of how, when and where users are logging in
* Pull data from other sources and add it to user profile, through [JavaScript rules](https://docs.auth0.com/rules)
## Create a free Auth0 account
* Go to [Auth0 website](https://auth0.com/signup)
* Hit the **SIGN UP** button in the upper-right corner

@@ -1,22 +0,50 @@

var fixture = require('./fixture/namespace');
var request = require('request');
var io = require('socket.io-client');
const fixture = require('./fixture/namespace');
const request = require('request');
const io = require('socket.io-client');
describe('authorizer with namespaces', function () {
describe('authorizer with namespaces', () => {
//start and stop the server
before(fixture.start);
after(fixture.stop);
describe('when the user is not logged in', function () {
describe('when the user is not logged in', () => {
it('should be able to connect to the default namespace', function (done){
var socket = io.connect('http://localhost:9000');
socket.once('hi', done);
it('should be able to connect to the default namespace', (done) => {
io.connect('http://localhost:9000')
.once('hi', () => done())
.on('error', done);
});
it('should not be able to connect to the admin namespace', function (done){
var socket = io.connect('http://localhost:9000/admin');
socket.once('disconnect', function () {
it('should not be able to connect to the admin namespace', (done) => {
io.connect('http://localhost:9000/admin')
.once('disconnect', () => done())
.once('hi admin', () => done(new Error('unauthenticated client was able to connect to the admin namespace')));
});
it('should not be able to connect to the admin_hs namespace', (done) => {
io.connect('http://localhost:9000/admin_hs')
.once('hi admin', () => done(new Error('unauthenticated client was able to connect to the admin_hs namespace')))
.on('error', (err) => {
if (err === 'Invalid namespace') { // SocketIO throws this error, if auth failed
return;
} else if (err && err.type == 'UnauthorizedError') {
done();
} else {
done(err);
}
});
});
});
describe('when the user is logged in', () => {
beforeEach((done) => {
request.post({
url: 'http://localhost:9000/login',
form: { username: 'jose', password: 'Pa123' },
json: true
}, (err, resp, body) => {
this.token = body.token;
done();

@@ -26,7 +54,18 @@ });

it('should do the authentication and connect', (done) => {
io.connect('http://localhost:9000/admin', { forceNew: true })
.on('hi admin', () => done())
.emit('authenticate', { token: this.token });
});
it('should do the authentication and connect without "forceNew"', (done) => {
io.connect('http://localhost:9000/admin', { forceNew: false })
.on('hi admin', () => done())
.emit('authenticate', { token: this.token });
});
});
describe('when the user is logged in', function() {
describe('when the user is logged in via handshake', () => {
beforeEach(function (done) {
beforeEach((done) => {
request.post({

@@ -36,21 +75,19 @@ url: 'http://localhost:9000/login',

json: true
}, function (err, resp, body) {
}, (err, resp, body) => {
this.token = body.token;
done();
}.bind(this));
});
});
it('should do the handshake and connect', function (done){
var socket = io.connect('http://localhost:9000/admin', {
'forceNew': true,
});
var token = this.token;
socket.on('connect', function(){
socket.on('authenticated', function () {
done();
}).emit('authenticate', { token: token });
});
it('should do the handshake and connect', (done) => {
io.connect('http://localhost:9000/admin_hs', { forceNew: true, query: 'token=' + this.token })
.once('hi admin', () => done());
});
it('should do the handshake and connect without "forceNew"', (done) => {
io.connect('http://localhost:9000/admin_hs', { forceNew: false, query: 'token=' + this.token })
.once('hi admin', () => done());
});
});
});

@@ -1,12 +0,10 @@

var fixture = require('./fixture');
var request = require('request');
var io = require('socket.io-client');
const fixture = require('./fixture');
const request = require('request');
const io = require('socket.io-client');
describe('authorizer without querystring', function () {
describe('authorizer without querystring', () => {
//start and stop the server
before(function (done) {
fixture.start({
handshake: false
} , done);
before((done) => {
fixture.start({ handshake: false }, done);
});

@@ -16,22 +14,14 @@

describe('when the user is not logged in', function () {
describe('when the user is not logged in', () => {
it('should close the connection after a timeout if no auth message is received', function (done){
var socket = io.connect('http://localhost:9000', {
forceNew: true
});
socket.once('disconnect', function () {
done();
});
it('should close the connection after a timeout if no auth message is received', (done) => {
io.connect('http://localhost:9000', { forceNew: true })
.once('disconnect', () => done());
});
it('should not respond echo', function (done){
var socket = io.connect('http://localhost:9000', {
'forceNew':true,
});
it('should not respond echo', (done) => {
io.connect('http://localhost:9000', { forceNew: true })
.on('echo-response', () => done(new Error('this should not happen')))
.emit('echo', { hi: 123 });
socket.on('echo-response', function () {
done(new Error('this should not happen'));
}).emit('echo', { hi: 123 });
setTimeout(done, 1200);

@@ -42,5 +32,5 @@ });

describe('when the user is logged in', function() {
describe('when the user is logged in', () => {
beforeEach(function (done) {
beforeEach((done) => {
request.post({

@@ -50,21 +40,18 @@ url: 'http://localhost:9000/login',

json: true
}, function (err, resp, body) {
}, (err, resp, body) => {
this.token = body.token;
done();
}.bind(this));
});
});
it('should do the handshake and connect', function (done){
var socket = io.connect('http://localhost:9000', {
'forceNew':true,
});
var token = this.token;
socket.on('connect', function(){
socket.on('echo-response', function () {
it('should do the authentication and connect', (done) => {
const socket = io.connect('http://localhost:9000', { forceNew: true });
socket
.on('echo-response', () => {
socket.close();
done();
}).on('authenticated', function () {
socket.emit('echo');
}).emit('authenticate', { token: token });
});
})
.on('authenticated', () => { socket.emit('echo'); })
.emit('authenticate', { token: this.token });
});

@@ -71,0 +58,0 @@ });

@@ -1,12 +0,12 @@

var fixture = require('./fixture/secret_function');
var request = require('request');
var io = require('socket.io-client');
const fixture = require('./fixture/secret_function');
const request = require('request');
const io = require('socket.io-client');
describe('authorizer with secret function', function () {
describe('authorizer with secret function', () => {
//start and stop the server
before(function (done) {
before((done) => {
fixture.start({
handshake: false
} , done);
}, done);
});

@@ -16,29 +16,19 @@

describe('when the user is not logged in', function () {
describe('when the user is not logged in', () => {
describe('and when token is not valid', function() {
beforeEach(function (done) {
describe('and when token is not valid', () => {
beforeEach((done) => {
request.post({
url: 'http://localhost:9000/login',
json: { username: 'invalid_signature', password: 'Pa123' }
}, function (err, resp, body) {
}, (err, resp, body) => {
this.invalidToken = body.token;
done();
}.bind(this));
});
});
it('should emit unauthorized', function (done){
var socket = io.connect('http://localhost:9000', {
'forceNew':true,
});
var invalidToken = this.invalidToken;
socket.on('unauthorized', function() {
done();
});
socket.on('connect', function(){
socket
.emit('authenticate', { token: invalidToken + 'ass' })
});
it('should emit unauthorized', (done) => {
io.connect('http://localhost:9000', { forceNew: true })
.on('unauthorized', () => done())
.emit('authenticate', { token: this.invalidToken + 'ass' })
});

@@ -49,28 +39,24 @@ });

describe('when the user is logged in', function() {
describe('when the user is logged in', () => {
beforeEach(function (done) {
beforeEach((done) => {
request.post({
url: 'http://localhost:9000/login',
json: { username: 'valid_signature', password: 'Pa123' }
}, function (err, resp, body) {
}, (err, resp, body) => {
this.token = body.token;
done();
}.bind(this));
});
});
it('should do the handshake and connect', function (done){
var socket = io.connect('http://localhost:9000', {
'forceNew':true,
});
var token = this.token;
socket.on('connect', function(){
socket.on('echo-response', function () {
it('should do the authentication and connect', (done) => {
const socket = io.connect('http://localhost:9000', { forceNew: true });
socket
.on('echo-response', () => {
socket.close();
done();
}).on('authenticated', function () {
socket.emit('echo');
})
.emit('authenticate', { token: token })
});
.on('authenticated', () => { socket.emit('echo'); })
.emit('authenticate', { token: this.token });
});

@@ -77,0 +63,0 @@ });

@@ -1,6 +0,6 @@

var fixture = require('./fixture/secret_function');
var request = require('request');
var io = require('socket.io-client');
const fixture = require('./fixture/secret_function');
const request = require('request');
const io = require('socket.io-client');
describe('authorizer with secret function', function () {
describe('authorizer with secret function', () => {

@@ -11,12 +11,10 @@ //start and stop the server

describe('when the user is not logged in', function () {
describe('when the user is not logged in', () => {
it('should emit error with unauthorized handshake', function (done){
var socket = io.connect('http://localhost:9000?token=boooooo', {
'forceNew': true
});
it('should emit error with unauthorized handshake', (done) => {
const socket = io.connect('http://localhost:9000?token=boooooo', { forceNew: true });
socket.on('error', function(err){
err.message.should.eql("jwt malformed");
err.code.should.eql("invalid_token");
socket.on('error', (err) => {
err.message.should.eql('jwt malformed');
err.code.should.eql('invalid_token');
socket.close();

@@ -29,44 +27,50 @@ done();

describe('when the user is logged in', function() {
describe('when the user is logged in', () => {
beforeEach(function (done) {
beforeEach((done) => {
request.post({
url: 'http://localhost:9000/login',
json: { username: 'valid_signature', password: 'Pa123' }
}, function (err, resp, body) {
}, (err, resp, body) => {
this.token = body.token;
done();
}.bind(this));
});
});
it('should do the handshake and connect', function (done){
var socket = io.connect('http://localhost:9000', {
'forceNew':true,
'query': 'token=' + this.token
it('should do the handshake and connect', (done) => {
const socket = io.connect('http://localhost:9000', {
forceNew: true,
query: 'token=' + this.token
});
socket.on('connect', function(){
socket.close();
done();
}).on('error', done);
socket
.on('connect', () => {
socket.close();
done();
})
.on('error', done);
});
});
describe('unsigned token', function() {
beforeEach(function () {
describe('unsigned token', () => {
beforeEach(() => {
this.token = 'eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJuYW1lIjoiSm9obiBGb28ifQ.';
});
it('should not do the handshake and connect', function (done){
var socket = io.connect('http://localhost:9000', {
'forceNew':true,
'query': 'token=' + this.token
it('should not do the handshake and connect', (done) => {
const socket = io.connect('http://localhost:9000', {
forceNew: true,
query: 'token=' + this.token
});
socket.on('connect', function () {
socket.close();
done(new Error('this shouldnt happen'));
}).on('error', function (err) {
socket.close();
err.message.should.eql("jwt signature is required");
done();
});
socket
.on('connect', () => {
socket.close();
done(new Error('this shouldnt happen'));
})
.on('error', (err) => {
socket.close();
err.message.should.eql('jwt signature is required');
done();
});
});

@@ -73,0 +77,0 @@ });

@@ -1,21 +0,20 @@

var fixture = require('./fixture');
var request = require('request');
var io = require('socket.io-client');
const Q = require('q');
const fixture = require('./fixture');
const request = require('request');
const io = require('socket.io-client');
describe('authorizer', function () {
describe('authorizer', () => {
//start and stop the server
before(fixture.start);
before((done) => { fixture.start({ }, done) });
after(fixture.stop);
describe('when the user is not logged in', function () {
it('should emit error with unauthorized handshake', function (done){
var socket = io.connect('http://localhost:9000?token=boooooo', {
'forceNew': true
describe('when the user is not logged in', () => {
it('should emit error with unauthorized handshake', (done) => {
const socket = io.connect('http://localhost:9000?token=boooooo', {
forceNew: true
});
socket.on('error', function(err){
err.message.should.eql("jwt malformed");
err.code.should.eql("invalid_token");
socket.on('error', (err) => {
err.message.should.eql('jwt malformed');
err.code.should.eql('invalid_token');
socket.close();

@@ -25,8 +24,6 @@ done();

});
});
describe('when the user is logged in', function() {
beforeEach(function (done) {
describe('when the user is logged in', () => {
before((done) => {
request.post({

@@ -36,41 +33,111 @@ url: 'http://localhost:9000/login',

json: true
}, function (err, resp, body) {
}, (err, resp, body) => {
this.token = body.token;
done();
}.bind(this));
});
});
it('should do the handshake and connect', function (done){
var socket = io.connect('http://localhost:9000', {
'forceNew':true,
'query': 'token=' + this.token
describe('authorizer disallows query string token when specified in startup options', () => {
before((done) => {
Q.ninvoke(fixture, 'stop')
.then(() => Q.ninvoke(fixture, 'start', { auth_header_required: true }))
.done(done);
});
socket.on('connect', function(){
socket.close();
done();
}).on('error', done);
after((done) => {
Q.ninvoke(fixture, 'stop')
.then(() => Q.ninvoke(fixture, 'start', { }))
.done(done);
});
it('auth headers are supported', (done) => {
const socket = io.connect('http://localhost:9000', {
forceNew: true,
extraHeaders: { Authorization: 'Bearer ' + this.token}
});
socket
.on('connect', () => {
socket.close();
done();
})
.on('error', done);
});
it('auth token in query string is disallowed', (done) => {
const socket = io.connect('http://localhost:9000', {
forceNew: true,
query: 'token=' + this.token
});
socket.on('error', (err) => {
err.message.should.eql('Server requires Authorization Header');
err.code.should.eql('missing_authorization_header');
socket.close();
done();
});
});
})
describe('authorizer all auth types allowed', () => {
before((done) => {
Q.ninvoke(fixture, 'stop')
.then(() => Q.ninvoke(fixture, 'start', {}))
.done(done);
})
it('auth headers are supported', (done) => {
const socket = io.connect('http://localhost:9000', {
forceNew: true,
extraHeaders: { Authorization: 'Bearer ' + this.token }
});
socket
.on('connect', () => {
socket.close();
done();
})
.on('error', done);
});
it('should do the handshake and connect', (done) => {
const socket = io.connect('http://localhost:9000', {
forceNew: true,
query: 'token=' + this.token
});
socket
.on('connect', () => {
socket.close();
done();
})
.on('error', done);
});
});
});
describe('unsgined token', function() {
beforeEach(function () {
describe('unsigned token', () => {
beforeEach(() => {
this.token = 'eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJuYW1lIjoiSm9obiBGb28ifQ.';
});
it('should not do the handshake and connect', function (done){
var socket = io.connect('http://localhost:9000', {
'forceNew':true,
'query': 'token=' + this.token
it('should not do the handshake and connect', (done) => {
const socket = io.connect('http://localhost:9000', {
forceNew: true,
query: 'token=' + this.token
});
socket.on('connect', function () {
socket.close();
done(new Error('this shouldnt happen'));
}).on('error', function (err) {
socket.close();
err.message.should.eql("jwt signature is required");
done();
});
socket
.on('connect', () => {
socket.close();
done(new Error('this shouldnt happen'));
})
.on('error', (err) => {
socket.close();
err.message.should.eql('jwt signature is required');
done();
});
});
});
});

@@ -1,18 +0,19 @@

var express = require('express');
var http = require('http');
'use strict'; // Node 4.x workaround
var socketIo = require('socket.io');
var socketio_jwt = require('../../lib');
const express = require('express');
const http = require('http');
var jwt = require('jsonwebtoken');
const socketIo = require('socket.io');
const socketio_jwt = require('../../lib');
var xtend = require('xtend');
var bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const xtend = require('xtend');
const bodyParser = require('body-parser');
const enableDestroy = require('server-destroy');
var server, sio;
var enableDestroy = require('server-destroy');
let sio;
exports.start = function (options, callback) {
exports.start = (options, callback) => {
if(typeof options == 'function'){
if (typeof options == 'function') {
callback = options;

@@ -28,8 +29,9 @@ options = {};

var app = express();
const app = express();
const server = http.createServer(app);
sio = socketIo.listen(server);
app.use(bodyParser.json());
app.post('/login', function (req, res) {
var profile = {
app.post('/login', (req, res) => {
const profile = {
first_name: 'John',

@@ -42,15 +44,11 @@ last_name: 'Doe',

// We are sending the profile inside the token
var token = jwt.sign(profile, options.secret, { expiresInMinutes: 60*5 });
const token = jwt.sign(profile, options.secret, { expiresIn: 60*60*5 });
res.json({token: token});
});
server = http.createServer(app);
sio = socketIo.listen(server);
if (options.handshake) {
sio.use(socketio_jwt.authorize(options));
sio.sockets.on('echo', function (m) {
sio.sockets.on('echo', (m) => {
sio.sockets.emit('echo-response', m);

@@ -61,4 +59,4 @@ });

.on('connection', socketio_jwt.authorize(options))
.on('authenticated', function (socket) {
socket.on('echo', function (m) {
.on('authenticated', (socket) => {
socket.on('echo', (m) => {
socket.emit('echo-response', m);

@@ -70,3 +68,3 @@ });

server.__sockets = [];
server.on('connection', function (c) {
server.on('connection', (c) => {
server.__sockets.push(c);

@@ -78,3 +76,3 @@ });

exports.stop = function (callback) {
exports.stop = (callback) => {
sio.close();

@@ -85,2 +83,2 @@ try {

callback();
};
};

@@ -1,14 +0,15 @@

var express = require('express');
var http = require('http');
'use strict'; // Node 4.x workaround
var socketIo = require('socket.io');
var socketio_jwt = require('../../lib');
const express = require('express');
const http = require('http');
var jwt = require('jsonwebtoken');
const socketIo = require('socket.io');
const socketio_jwt = require('../../lib');
var xtend = require('xtend');
var bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const xtend = require('xtend');
const enableDestroy = require('server-destroy');
const bodyParser = require('body-parser');
var server, sio;
var enableDestroy = require('server-destroy');
let sio;

@@ -20,5 +21,5 @@ /**

*/
exports.start = function (callback) {
exports.start = (callback) => {
options = {
const options = {
secret: 'aaafoo super sercret',

@@ -29,8 +30,9 @@ timeout: 1000,

var app = express();
const app = express();
const server = http.createServer(app);
sio = socketIo.listen(server);
app.use(bodyParser.json());
app.post('/login', function (req, res) {
var profile = {
app.post('/login', (req, res) => {
const profile = {
first_name: 'John',

@@ -43,23 +45,29 @@ last_name: 'Doe',

// We are sending the profile inside the token
var token = jwt.sign(profile, options.secret, { expiresInMinutes: 60*5 });
res.json({token: token});
const token = jwt.sign(profile, options.secret, { expiresIn: 60*60*5 });
res.json({ token: token });
});
server = http.createServer(app);
sio = socketIo.listen(server);
sio.on('connection', function (socket) {
// Global namespace (public)
sio.on('connection', (socket) => {
socket.emit('hi');
});
var admin_nsp = sio.of('/admin');
// Second roundtrip
const admin_nsp = sio.of('/admin');
admin_nsp.on('connection', socketio_jwt.authorize(options))
.on('authenticated', function (socket) {
socket.emit('hi admin');
});
.on('authenticated', (socket) => {
socket.emit('hi admin');
});
// One roundtrip
const admin_nsp_hs = sio.of('/admin_hs');
admin_nsp_hs.use(socketio_jwt.authorize(xtend(options, { handshake: true })));
admin_nsp_hs.on('connection', (socket) => {
socket.emit('hi admin');
});
server.listen(9000, callback);

@@ -69,3 +77,3 @@ enableDestroy(server);

exports.stop = function (callback) {
exports.stop = (callback) => {
sio.close();

@@ -76,2 +84,2 @@ try {

callback();
};
};

@@ -1,17 +0,18 @@

var express = require('express');
var http = require('http');
'use strict'; // Node 4.x workaround
var socketIo = require('socket.io');
var socketio_jwt = require('../../lib');
const express = require('express');
const http = require('http');
var jwt = require('jsonwebtoken');
const socketIo = require('socket.io');
const socketio_jwt = require('../../lib');
var xtend = require('xtend');
var bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const xtend = require('xtend');
const bodyParser = require('body-parser');
const enableDestroy = require('server-destroy');
var server, sio;
var enableDestroy = require('server-destroy');
let sio;
exports.start = function (options, callback) {
var SECRETS = {
exports.start = (options, callback) => {
const SECRETS = {
123: 'aaafoo super sercret',

@@ -21,3 +22,3 @@ 555: 'other'

if(typeof options == 'function'){
if (typeof options == 'function') {
callback = options;

@@ -28,3 +29,3 @@ options = {};

options = xtend({
secret: function(request, decodedToken, callback) {
secret: (request, decodedToken, callback) => {
callback(null, SECRETS[decodedToken.id]);

@@ -36,8 +37,9 @@ },

var app = express();
const app = express();
const server = http.createServer(app);
sio = socketIo.listen(server);
app.use(bodyParser.json());
app.post('/login', function (req, res) {
var profile = {
app.post('/login', (req, res) => {
const profile = {
first_name: 'John',

@@ -50,15 +52,10 @@ last_name: 'Doe',

// We are sending the profile inside the token
var token = jwt.sign(profile, SECRETS[123], { expiresIn: 60*60*5 });
const token = jwt.sign(profile, SECRETS[123], { expiresIn: 60*60*5 });
res.json({token: token});
});
server = http.createServer(app);
sio = socketIo.listen(server);
if (options.handshake) {
sio.use(socketio_jwt.authorize(options));
sio.sockets.on('echo', function (m) {
sio.sockets.on('echo', (m) => {
sio.sockets.emit('echo-response', m);

@@ -69,4 +66,4 @@ });

.on('connection', socketio_jwt.authorize(options))
.on('authenticated', function (socket) {
socket.on('echo', function (m) {
.on('authenticated', (socket) => {
socket.on('echo', (m) => {
socket.emit('echo-response', m);

@@ -78,3 +75,3 @@ });

server.__sockets = [];
server.on('connection', function (c) {
server.on('connection', (c) => {
server.__sockets.push(c);

@@ -87,3 +84,3 @@ });

exports.stop = function (callback) {
exports.stop = (callback) => {
sio.close();

@@ -96,2 +93,1 @@ try {

};

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc