SocketCluster Middleware HandShake with promise

806 Views Asked by At

Im building an app that serve both http and ws. Users login first over HTTP to a Laravel Server. That returns a JWT that is used to allow login over WS.

Ihv added a MIDDLEWARE_HANDSHAKE that gets the token and make a request to Laravel Server to ask if that token is valid and the user has access to WS (Not every logged user is allowed to WS);

Client code:

var options = {
    host: '127.0.0.1:3000',
    query: {
        source: 'web',
        token: '',
    }
};

var socket;

$.post('http://127.0.0.1:8000/authenticate', {
    email: '[email protected]',
    password: '1234'
}, function(data, textStatus, xhr) {
    options.query.token = data.token;

    //ALL PERFECT UNTILL HERE

    // Initiate the connection to the ws server
    socket = socketCluster.connect(options)
        .on('connect', function(data) {
            console.log('CONNECTED', data);
        })
        .on('error', function(data) {
            console.log('ERROR', data.message);
        });
});

SocketCluster Server code:

scServer.addMiddleware(scServer.MIDDLEWARE_HANDSHAKE, function(request, next) {
    var query = url.parse(request.url, true).query;
    switch (query.source) {
        case 'web':
        case 'mobile-app':
            validateUser(query)
                .then((response) => {
                    next(); //Allowed
                })
                .catch((code) => {
                    next(code); //Blocked with StatusCode
                });
            break;

        default:
            next(true, 'NOT_AUTHORIZED'); // Block
            break;
    }
});

validateUser = (credentials = {}) => {
    return new Promise((resolve, reject) => {
        request({ url: API + 'webSocket/users/' + credentials.token, method: 'GET' }, (error, response, body) => {
            if (response.statusCode === 200) {
                resolve(body);
            }
            reject(response.statusCode);
        });
    });

};

While implementing this middleware like this i keep getting this response from ws server even when validation is successfull:

WebSocket connection to 'ws://127.0.0.1:3000/socketcluster/?source=web&token=<_TOKEN_>' failed: Connection closed before receiving a handshake response

(index):149 ERROR Socket hung up

But, if i implement the HANDSHAKE_MIDDLEWARE like this:

scServer.addMiddleware(scServer.MIDDLEWARE_HANDSHAKE, function(request, next) {
    var validUser = true;
    if (validUser){
         return next();
    }
    return next('NOT_A_VALID_USER');
});

All goes fine:

CONNECTED Object {id: "W067vqBc9Ii8MuIqAAAC", pingTimeout: 20000, isAuthenticated: true, authToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6I…xOTV9.E4bLPh4Vjk9ULvfhW6prjBbVt0vOD32k63L1vlDtGrU"}

So the problem seems to be in the Promise callback.

Any advice if this is not the right way to implement?

Thanks.

1

There are 1 best solutions below

0
On

A big reason why JWT is used on SocketCluster is to handle logging in and authentication, have you considered just using WS?

Take a look at SocketCluster authentication.


Just how your current HTTP code check the login data, you can do the same for WS and use socket.setAuthToken to set the token (here is an example that I used in my project):

socket.setAuthToken({
    email: credentials.email,
    id: returnedData.id,
    permission: returnedData.permission
});

You can then do requests to the WS server still using on/emit, and do a check to see if they are authenticated. Here's a modified snippet of my authCheck function:

const token = socket.getAuthToken();

if (token && token.email) {
    console.log('Token Valid, User is: ', token.email);
    // user validated - continue with your code
} else {
    console.log('Token Invalid, User not authenticated.');
    // respond with error message to the user
}