Add Supabase JWT authorization middleware, config parsing, and WebSocket token verification

This commit is contained in:
2026-07-17 22:46:26 +04:00
parent 9c9632343d
commit a5d2ee32c6
8 changed files with 753 additions and 395 deletions
+14
View File
@@ -26,6 +26,7 @@ type Config struct {
DevMode bool // If true, allow multiple clients without auth
DatabaseURL string // Postgres connection string; required at runtime
JWTSecret string // Supabase JWT Secret for signature verification
UDPVideoAddr string // UDP address to listen on for video, e.g. ":9999"
ESPCmdPort int // Port on ESP32 that listens for commands, e.g. 8888
@@ -39,6 +40,14 @@ type Config struct {
func Load() (*Config, error) {
loadDotEnv()
jwtSecret := getEnv("X0GP_JWT_SECRET", "")
if jwtSecret == "" {
jwtSecret = getEnv("JWT_SECRET", "")
}
if jwtSecret == "" {
jwtSecret = getEnv("SUPABASE_JWT_SECRET", "")
}
c := &Config{
HTTPAddr: getEnv("X0GP_HTTP_ADDR", ":8080"),
TickRate: getEnvInt("X0GP_TICK_RATE", 60),
@@ -47,10 +56,15 @@ func Load() (*Config, error) {
SnapshotRate: getEnvInt("X0GP_SNAPSHOT_RATE", 30),
DevMode: getEnvBool("X0GP_DEV_MODE", true),
DatabaseURL: getEnv("DATABASE_URL", ""),
JWTSecret: jwtSecret,
UDPVideoAddr: getEnv("X0GP_UDP_VIDEO_ADDR", ":9999"),
ESPCmdPort: getEnvInt("X0GP_ESP_CMD_PORT", 8888),
}
if !c.DevMode && c.JWTSecret == "" {
return nil, fmt.Errorf("JWT secret (X0GP_JWT_SECRET / JWT_SECRET) is required when DevMode is disabled")
}
if c.TickRate <= 0 || c.TickRate > 240 {
return nil, fmt.Errorf("X0GP_TICK_RATE must be in (0, 240], got %d", c.TickRate)
}