Add WebSocket auth — JWT token validation on WS upgrade handshake

- websocket.nim: check Authorization Bearer token before WebSocket upgrade
- httpserver.nim: pass config + jwtSecret to WsServer
This commit is contained in:
2026-05-07 00:38:38 +03:00
parent 18af892232
commit 29425c45f8
2 changed files with 28 additions and 4 deletions
+2 -2
View File
@@ -42,11 +42,11 @@ proc newHttpServer*(config: BaraConfig): HttpServer =
let db = newLSMTree(dataDir) let db = newLSMTree(dataDir)
let ctx = newExecutionContext(db) let ctx = newExecutionContext(db)
ctx.txnManager = newTxnManager() ctx.txnManager = newTxnManager()
let ws = newWsServer() let secret = if config.jwtSecret.len > 0: config.jwtSecret else: "baradb-default-secret-change-in-production!"
let ws = newWsServer(config, secret)
ctx.onChange = proc(ev: ChangeEvent) = ctx.onChange = proc(ev: ChangeEvent) =
let msg = $ev.kind & " " & ev.table let msg = $ev.kind & " " & ev.table
asyncCheck ws.broadcastToTable(ev.table, msg) asyncCheck ws.broadcastToTable(ev.table, msg)
let secret = if config.jwtSecret.len > 0: config.jwtSecret else: "baradb-default-secret-change-in-production!"
HttpServer(config: config, running: false, db: db, ctx: ctx, HttpServer(config: config, running: false, db: db, ctx: ctx,
secretKey: secret, secretKey: secret,
metrics: Metrics(), ws: ws) metrics: Metrics(), ws: ws)
+26 -2
View File
@@ -5,6 +5,8 @@ import std/strutils
import std/tables import std/tables
import std/base64 import std/base64
import std/sets import std/sets
import config
import jwt as jwtlib
type type
WsFrame = object WsFrame = object
@@ -24,11 +26,14 @@ type
clients*: Table[int, WsClient] clients*: Table[int, WsClient]
nextId: int nextId: int
running: bool running: bool
config*: BaraConfig
secretKey*: string
onInsert*: proc (table, key, value: string) {.closure.} onInsert*: proc (table, key, value: string) {.closure.}
onDelete*: proc (table, key: string) {.closure.} onDelete*: proc (table, key: string) {.closure.}
proc newWsServer*(): WsServer = proc newWsServer*(cfg: BaraConfig = defaultConfig(), secret: string = ""): WsServer =
WsServer(clients: initTable[int, WsClient](), nextId: 1, running: false) WsServer(clients: initTable[int, WsClient](), nextId: 1, running: false,
config: cfg, secretKey: secret)
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
# WebSocket frame encoding/decoding (RFC 6455) # WebSocket frame encoding/decoding (RFC 6455)
@@ -270,6 +275,25 @@ proc handleConnection(server: WsServer, client: AsyncSocket) {.async.} =
client.close() client.close()
return return
# Auth check
if server.config.authEnabled:
let authHeader = headers.getOrDefault("authorization", "")
if authHeader.len == 0 or not authHeader.startsWith("Bearer "):
await client.send("HTTP/1.1 401 Unauthorized\r\n\r\n")
client.close()
return
let tokenStr = authHeader[7..^1]
try:
let token = tokenStr.toJWT()
if not token.verify(server.secretKey, HS256):
await client.send("HTTP/1.1 401 Unauthorized\r\n\r\n")
client.close()
return
except:
await client.send("HTTP/1.1 401 Unauthorized\r\n\r\n")
client.close()
return
let acceptKey = computeAcceptKey(wsKey) let acceptKey = computeAcceptKey(wsKey)
var response = "HTTP/1.1 101 Switching Protocols\r\n" var response = "HTTP/1.1 101 Switching Protocols\r\n"