package auth import ( "fmt" "time" "github.com/golang-jwt/jwt/v5" ) // JWTService hanterar JWT-token generering och validering type JWTService struct { secret []byte issuer string audience string } // NewJWTService skapar en ny JWTService func NewJWTService(secret, issuer, audience string) *JWTService { return &JWTService{ secret: []byte(secret), issuer: issuer, audience: audience, } } // GenerateToken skapar en ny JWT-token func (s *JWTService) GenerateToken(sub, email, role string) (string, error) { now := time.Now() claims := jwt.MapClaims{ "sub": sub, "email": email, "role": role, "iss": s.issuer, "aud": s.audience, "iat": now.Unix(), "exp": now.Add(30 * 24 * time.Hour).Unix(), // 30 dagar } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(s.secret) } // ValidateToken validerar en JWT-token func (s *JWTService) ValidateToken(tokenString string) (*Claims, error) { if len(tokenString) < 10 { return nil, fmt.Errorf("token too short: %d", len(tokenString)) } token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } return s.secret, nil }) if err != nil { return nil, fmt.Errorf("parse error: %w", err) } if !token.Valid { return nil, fmt.Errorf("token invalid") } mapClaims, ok := token.Claims.(jwt.MapClaims) if !ok { return nil, fmt.Errorf("invalid claims format") } claims := &Claims{ Sub: getString(mapClaims, "sub"), Email: getString(mapClaims, "email"), Iss: getString(mapClaims, "iss"), Aud: getString(mapClaims, "aud"), Exp: getInt64(mapClaims, "exp"), Iat: getInt64(mapClaims, "iat"), } // Hantera roles if roles, ok := mapClaims["roles"]; ok { switch v := roles.(type) { case []interface{}: claims.Roles = make([]string, len(v)) for i, r := range v { claims.Roles[i] = fmt.Sprint(r) } case []string: claims.Roles = v case string: claims.Roles = []string{v} } } // Hantera role (singular) if role, ok := mapClaims["role"].(string); ok && role != "" { claims.Roles = append(claims.Roles, role) } if err := claims.Valid(); err != nil { return nil, err } return claims, nil } func getString(m jwt.MapClaims, key string) string { if v, ok := m[key].(string); ok { return v } return "" } func getInt64(m jwt.MapClaims, key string) int64 { switch v := m[key].(type) { case float64: return int64(v) case int64: return v case int: return int64(v) default: return 0 } }