From dfce15a74c3837fe1a0c0acb1f50cce6cb59a812 Mon Sep 17 00:00:00 2001 From: Finn Dittmar Date: Fri, 9 Jan 2026 20:45:48 +0100 Subject: [PATCH] Add support that API-Keys authenticate sockets --- server/SocketAuthority.js | 52 +++++++++++++++++++++++++++++++------ server/auth/TokenManager.js | 1 - 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/server/SocketAuthority.js b/server/SocketAuthority.js index ad55f6605..e47a3408a 100644 --- a/server/SocketAuthority.js +++ b/server/SocketAuthority.js @@ -249,22 +249,58 @@ class SocketAuthority { async authenticateSocket(socket, token) { // we don't use passport to authenticate the jwt we get over the socket connection. // it's easier to directly verify/decode it. - // TODO: Support API keys for web socket connections const token_data = TokenManager.validateAccessToken(token) - if (!token_data?.userId) { + if (!token_data) { // Token invalid Logger.error('Cannot validate socket - invalid token') return socket.emit('auth_failed', { message: 'Invalid token' }) } - // get the user via the id from the decoded jwt. - const user = await Database.userModel.getUserByIdOrOldId(token_data.userId) - if (!user) { - // user not found - Logger.error('Cannot validate socket - invalid token') - return socket.emit('auth_failed', { message: 'Invalid token' }) + let user = null + + if (token_data.type === 'api') { + // Api key based authentication + const apiKey = await Database.apiKeyModel.getById(token_data.keyId) + + if (!apiKey?.isActive) { + Logger.error('Cannot validate socket - API key not found or inactive') + return socket.emit('auth_failed', { message: 'Invalid API key' }) + } + + if (token_data.exp && token_data.exp < Date.now() / 1000) { + apiKey.isActive = false + await apiKey.save() + Logger.info(`[SocketAuthority] API key ${apiKey.id} is expired - deactivated`) + return socket.emit('auth_failed', { message: 'API key expired' }) + } + + user = await Database.userModel.getUserById(apiKey.userId) + if (!user) { + Logger.error('Cannot validate socket - user not found for API key') + return socket.emit('auth_failed', { message: 'Invalid API key' }) + } + } else { + // JWT based authentication + if (!token_data.userId) { + Logger.error('Cannot validate socket - invalid token') + return socket.emit('auth_failed', { message: 'Invalid token' }) + } + + if (token_data.exp && token_data.exp < Date.now() / 1000) { + Logger.error('Cannot validate socket - token expired') + return socket.emit('auth_failed', { message: 'Token expired' }) + } + + // get the user via the id from the decoded jwt. + user = await Database.userModel.getUserByIdOrOldId(token_data.userId) + if (!user) { + // user not found + Logger.error('Cannot validate socket - invalid token') + return socket.emit('auth_failed', { message: 'Invalid token' }) + } } + if (!user.isActive) { Logger.error('Cannot validate socket - user is not active') return socket.emit('auth_failed', { message: 'Invalid user' }) diff --git a/server/auth/TokenManager.js b/server/auth/TokenManager.js index faa6774a3..a1b08b17a 100644 --- a/server/auth/TokenManager.js +++ b/server/auth/TokenManager.js @@ -68,7 +68,6 @@ class TokenManager { /** * Function to validate a jwt token for a given user * Used to authenticate socket connections - * TODO: Support API keys for web socket connections * * @param {string} token * @returns {Object} tokens data