fix: dynamic jwt secret

This commit is contained in:
gian2dchris
2025-11-10 17:44:53 +02:00
committed by Hugo
parent bab69aea84
commit 5769f8782b
6 changed files with 39 additions and 6 deletions

View File

@@ -45,7 +45,7 @@ func (api *API) handleLogin(c *gin.Context) {
}
if api.UserService.Authenticate(loginUser.Username, loginUser.Password) {
token, err := generateToken(loginUser.Username)
token, err := generateToken(loginUser.Username, api.Config.API.JWTSecret)
if err != nil {
log.Info("Token generation failed for user %s: %v", loginUser.Username, err)
c.JSON(http.StatusInternalServerError, gin.H{

View File

@@ -1,6 +1,7 @@
package api
import (
"encoding/base64"
"fmt"
"net/http"
"strings"
@@ -12,7 +13,6 @@ import (
const (
tokenDuration = 5 * time.Minute
secret = "kMNSRwKip7Yet4rb2z8"
)
func (api *API) authMiddleware() gin.HandlerFunc {
@@ -37,7 +37,7 @@ func (api *API) authMiddleware() gin.HandlerFunc {
return
}
claims, err := parseToken(cookie)
claims, err := parseToken(cookie, api.Config.API.JWTSecret)
if err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"})
return
@@ -66,7 +66,7 @@ func (api *API) authMiddleware() gin.HandlerFunc {
timeUntilExpiration := expiration - now
if timeUntilExpiration <= halfDurationSeconds {
newToken, err := generateToken(username)
newToken, err := generateToken(username, api.Config.API.JWTSecret)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Failed to renew token"})
return
@@ -80,11 +80,15 @@ func (api *API) authMiddleware() gin.HandlerFunc {
}
}
func parseToken(tokenString string) (jwt.MapClaims, error) {
func parseToken(tokenString string, b64secret string) (jwt.MapClaims, error) {
token, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
}
secret, err := base64.RawURLEncoding.DecodeString(b64secret)
if err != nil {
return "", err
}
return []byte(secret), nil
})
if err != nil || !token.Valid {
@@ -99,7 +103,7 @@ func parseToken(tokenString string) (jwt.MapClaims, error) {
return claims, nil
}
func generateToken(username string) (string, error) {
func generateToken(username string, b64secret string) (string, error) {
now := time.Now()
claims := jwt.MapClaims{
"username": username,
@@ -107,6 +111,10 @@ func generateToken(username string) (string, error) {
"iat": now.Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
secret, err := base64.RawURLEncoding.DecodeString(b64secret)
if err != nil {
return "", err
}
return token.SignedString([]byte(secret))
}

View File

@@ -45,6 +45,7 @@ type RateLimitConfig struct {
type APIConfig struct {
Port int `yaml:"port" json:"port"`
Authentication bool `yaml:"authentication" json:"authentication"`
JWTSecret string `yaml:"jwtSecret" json:"-"`
RateLimit RateLimitConfig `yaml:"rateLimit" json:"rateLimit"`
}

View File

@@ -1,7 +1,9 @@
package settings
import (
"crypto/rand"
"crypto/tls"
"encoding/base64"
"fmt"
"goaway/backend/logging"
"net"
@@ -83,6 +85,16 @@ func (config *Config) Update(updatedSettings Config) {
config.Save()
}
func GenerateSecret() string {
secret := make([]byte, 32)
_, err := rand.Read(secret)
if err != nil {
log.Error("Failed to generate secret: %v", err)
return ""
}
return base64.RawURLEncoding.EncodeToString(secret)
}
func createDefaultSettings(filePath string) (Config, error) {
defaultConfig := Config{
DNS: DNSConfig{
@@ -110,6 +122,7 @@ func createDefaultSettings(filePath string) (Config, error) {
API: APIConfig{
Port: getEnvAsIntWithDefault("WEBSITE_PORT", 8080),
Authentication: true,
JWTSecret: GenerateSecret(),
RateLimit: RateLimitConfig{
Enabled: true,
MaxTries: 5,

View File

@@ -1,6 +1,7 @@
package setup
import (
"encoding/base64"
"fmt"
"os"
"strconv"
@@ -133,6 +134,12 @@ func InitializeSettings(flags *SetFlags) *settings.Config {
}
UpdateConfig(&config, flags)
secret, err := base64.RawURLEncoding.DecodeString(config.API.JWTSecret)
if err != nil || len(secret) == 0 {
config.API.JWTSecret = settings.GenerateSecret()
}
config.Save()
return &config

View File

@@ -52,6 +52,10 @@ api:
# Set to true for increased security.
authentication: true
# Secret key used for signing JWT tokens.
# If empty, a random key will be generated automatically.
jwtSecret: ""
# Currently only protects the login route
rateLimit:
# Enable or disable the usage of rate limiting