2025-11-23 22:49:46 +07:00

132 lines
3.0 KiB
Go

// internal/config/jwt.go
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
}