Lichtwerkstatt / XRTL_SPA

Single Page Application for XRTL Remote Lab
https://xrtl.uni-jena.de/
GNU Affero General Public License v3.0
2 stars 3 forks source link

authentication not working in local environment #118

Closed doomke closed 1 year ago

doomke commented 1 year ago

We are currently using Json Web Tokens (JWT) to authenticate our clients with the socket server. To gather the payload for the token, the microcontrollers are connecting to an NTP server to query the current time and set the expiration date of the token to one week in the future.

However, this approach only works if the WiFi that the hardware connects to has (proper) internet access and fails if the setup is to be used in an exclusively local network. We can therefore not operate the setup in a local environment.

In order for it to work locally in upcoming events, we need to:

As far as I can see, we have several options to address this (additional ideas welcome):

  1. get rid of JWT
    1. deactivate authentication completely
    2. use an alternative methode of authentication
  2. synchronize time locally
    1. set up a local NTP server
    2. send current server time as part of an extended socket.io handshake
  3. find a workaround using JWT
    1. ommit all time information, tokens never expire (probably unsafe)
    2. add an option on hardware site to have a fixed expiration date without NTP synchronization

As of now I implemented 3.ii and it seems to work so far, but it feels like a dirty workaround that opens up for other issues. I would much prefere 2.ii as it offers an automatic fallback in case no NTP server is available or could replace the NTP query altogether.

doomke commented 1 year ago

We can add another middleware before the authentication:

io.use((socket, next) => {
    socket.emit('time', Date.now());
    next();
})

io.use((socket, next) => {
    if (socket.handshake.auth && socket.handshake.auth.token) {
        jwt.verify(socket.handshake.auth.token, 'keysecret', (err, decoded) => {
            if (err) return next(new Error('Authentication error'));
            socket.decoded = decoded;
            //exp = decoded.iat + 1800000;
            next();
        });
    }
    else {
        console.log('Authentication failed!')
        next(new Error('Authentication error'));
    }
})

The idea is to send the current time with every handshake before authenticating. This should provide a fallback to whatever the server time might be in a local environment.

doomke commented 1 year ago

As we are signing the JWT on client side anyway, the timestamps are arbitrary and will be omitted. Expiration of the connection is handled by the server when receiving the tokens.