mirror of
https://github.com/Thream/socketio-jwt.git
synced 2024-07-21 09:38:31 +02:00
dac693930b
Next step would not execute because no function(socket, next) was returned in case of successful verification in the 'one roundtrip' (handshake) approach. Returning auth.success instead of just executing it solves this. Fixes #51
153 lines
4.1 KiB
JavaScript
153 lines
4.1 KiB
JavaScript
var xtend = require('xtend');
|
|
var jwt = require('jsonwebtoken');
|
|
var UnauthorizedError = require('./UnauthorizedError');
|
|
|
|
function noQsMethod(options) {
|
|
var defaults = { required: true };
|
|
options = xtend(defaults, options);
|
|
|
|
return function (socket) {
|
|
var server = this.server || socket.server;
|
|
|
|
if (!server.$emit) {
|
|
//then is socket.io 1.0
|
|
var Namespace = Object.getPrototypeOf(server.sockets).constructor;
|
|
if (!~Namespace.events.indexOf('authenticated')) {
|
|
Namespace.events.push('authenticated');
|
|
}
|
|
}
|
|
|
|
if(options.required){
|
|
var auth_timeout = setTimeout(function () {
|
|
socket.disconnect('unauthorized');
|
|
}, options.timeout || 5000);
|
|
}
|
|
|
|
socket.on('authenticate', function (data) {
|
|
if(options.required){
|
|
clearTimeout(auth_timeout);
|
|
}
|
|
jwt.verify(data.token, options.secret, options, function(err, decoded) {
|
|
// 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
|
|
});
|
|
socket.emit('unauthorized', error, function() {
|
|
socket.disconnect('unauthorized');
|
|
});
|
|
return; // stop logic, socket will be close on next tick
|
|
}
|
|
};
|
|
|
|
if (err) {
|
|
return onError(err, 'invalid_token');
|
|
}
|
|
|
|
// success handler
|
|
var onSuccess = function(){
|
|
socket.decoded_token = decoded;
|
|
socket.emit('authenticated');
|
|
if (server.$emit) {
|
|
server.$emit('authenticated', socket);
|
|
} else {
|
|
//try getting the current namespace otherwise fallback to all sockets.
|
|
var namespace = (server.nsps && socket.nsp &&
|
|
server.nsps[socket.nsp.name]) ||
|
|
server.sockets;
|
|
|
|
// explicit namespace
|
|
namespace.emit('authenticated', socket);
|
|
}
|
|
};
|
|
|
|
if(options.additional_auth && typeof options.additional_auth === 'function') {
|
|
options.additional_auth(decoded, onSuccess, onError);
|
|
} else {
|
|
onSuccess();
|
|
}
|
|
});
|
|
});
|
|
|
|
};
|
|
}
|
|
|
|
function authorize(options, onConnection) {
|
|
if (!options.handshake) {
|
|
return noQsMethod(options);
|
|
}
|
|
|
|
var defaults = {
|
|
success: function(data, accept){
|
|
if (data.request) {
|
|
accept();
|
|
} else {
|
|
accept(null, true);
|
|
}
|
|
},
|
|
fail: function(error, data, accept){
|
|
if (data.request) {
|
|
accept(error);
|
|
} else {
|
|
accept(null, false);
|
|
}
|
|
}
|
|
};
|
|
|
|
var auth = xtend(defaults, options);
|
|
|
|
return function(data, accept){
|
|
var token, error;
|
|
var req = data.request || data;
|
|
var authorization_header = (req.headers || {}).authorization;
|
|
|
|
if (authorization_header) {
|
|
var parts = authorization_header.split(' ');
|
|
if (parts.length == 2) {
|
|
var scheme = parts[0],
|
|
credentials = parts[1];
|
|
|
|
if (scheme.toLowerCase() === 'bearer') {
|
|
token = credentials;
|
|
}
|
|
} else {
|
|
error = new UnauthorizedError('credentials_bad_format', {
|
|
message: 'Format is Authorization: Bearer [token]'
|
|
});
|
|
return auth.fail(error, data, accept);
|
|
}
|
|
}
|
|
|
|
//get the token from query string
|
|
if (req._query && req._query.token) {
|
|
token = req._query.token;
|
|
}
|
|
else if (req.query && req.query.token) {
|
|
token = req.query.token;
|
|
}
|
|
|
|
if (!token) {
|
|
error = new UnauthorizedError('credentials_required', {
|
|
message: 'No Authorization header was found'
|
|
});
|
|
return auth.fail(error, data, accept);
|
|
}
|
|
|
|
jwt.verify(token, options.secret, options, function(err, decoded) {
|
|
|
|
if (err) {
|
|
error = new UnauthorizedError('invalid_token', err);
|
|
return auth.fail(error, data, accept);
|
|
}
|
|
|
|
data.decoded_token = decoded;
|
|
|
|
return auth.success(data, accept);
|
|
});
|
|
};
|
|
}
|
|
|
|
exports.authorize = authorize;
|