package config import ( "errors" "os" "time" "github.com/golang-jwt/jwt/v5" ) var jwtConfig *JWTConfig // JWTConfig holds JWT configuration type JWTConfig struct { SecretKey string ExpirationHours int Issuer string } // JWTClaims represents the JWT claims type JWTClaims struct { UserID uint `json:"user_id"` Email string `json:"email"` Role string `json:"role"` jwt.RegisteredClaims } // InitJWT initializes JWT configuration func InitJWT() { secretKey := os.Getenv("JWT_SECRET_KEY") if secretKey == "" { secretKey = "your-secret-key-change-this-in-production" // Default for development } jwtConfig = &JWTConfig{ SecretKey: secretKey, ExpirationHours: 24 * 7, // 7 days Issuer: "lost-and-found-system", } } // GetJWTConfig returns JWT configuration func GetJWTConfig() JWTConfig { if jwtConfig == nil { InitJWT() } return *jwtConfig } // GenerateToken generates a new JWT token for a user func GenerateToken(userID uint, email, role string) (string, error) { config := GetJWTConfig() // Create claims claims := JWTClaims{ UserID: userID, Email: email, Role: role, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * time.Duration(config.ExpirationHours))), IssuedAt: jwt.NewNumericDate(time.Now()), Issuer: config.Issuer, }, } // Create token token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) // Sign token with secret key tokenString, err := token.SignedString([]byte(config.SecretKey)) if err != nil { return "", err } return tokenString, nil } // ValidateToken validates a JWT token and returns the claims func ValidateToken(tokenString string) (*JWTClaims, error) { config := GetJWTConfig() // Parse token token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) { // Validate signing method if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, errors.New("invalid signing method") } return []byte(config.SecretKey), nil }) if err != nil { return nil, err } // Extract claims if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid { return claims, nil } return nil, errors.New("invalid token") } // RefreshToken generates a new token with extended expiration func RefreshToken(oldTokenString string) (string, error) { // Validate old token claims, err := ValidateToken(oldTokenString) if err != nil { return "", err } // Generate new token with same user info return GenerateToken(claims.UserID, claims.Email, claims.Role) } // ExtractUserID extracts user ID from token string func ExtractUserID(tokenString string) (uint, error) { claims, err := ValidateToken(tokenString) if err != nil { return 0, err } return claims.UserID, nil } // ExtractRole extracts role from token string func ExtractRole(tokenString string) (string, error) { claims, err := ValidateToken(tokenString) if err != nil { return "", err } return claims.Role, nil }