package auth import ( "crypto/rand" "encoding/hex" "strings" "time" "github.com/gofiber/fiber/v2" "github.com/golang-jwt/jwt/v5" ) var jwtSecret []byte func Init(secret string) { jwtSecret = []byte(secret) } // GenerateAPIKey creates a new API key for agents func GenerateAPIKey() string { bytes := make([]byte, 32) rand.Read(bytes) return "ophion_" + hex.EncodeToString(bytes) } // GenerateJWT creates a JWT token for users func GenerateJWT(userID string, email string) (string, error) { claims := jwt.MapClaims{ "sub": userID, "email": email, "iat": time.Now().Unix(), "exp": time.Now().Add(24 * time.Hour).Unix(), } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(jwtSecret) } // ValidateJWT validates a JWT token func ValidateJWT(tokenString string) (*jwt.MapClaims, error) { token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { return jwtSecret, nil }) if err != nil || !token.Valid { return nil, err } claims, ok := token.Claims.(jwt.MapClaims) if !ok { return nil, jwt.ErrInvalidKey } return &claims, nil } // AuthMiddleware protects routes func AuthMiddleware() fiber.Handler { return func(c *fiber.Ctx) error { authHeader := c.Get("Authorization") if authHeader == "" { return c.Status(401).JSON(fiber.Map{ "error": "Missing authorization header", }) } // Support both "Bearer " and API keys token := strings.TrimPrefix(authHeader, "Bearer ") // Check if it's an API key if strings.HasPrefix(token, "ophion_") { // TODO: Validate API key against database c.Locals("auth_type", "api_key") c.Locals("api_key", token) return c.Next() } // Validate JWT claims, err := ValidateJWT(token) if err != nil { return c.Status(401).JSON(fiber.Map{ "error": "Invalid token", }) } c.Locals("auth_type", "jwt") c.Locals("user_id", (*claims)["sub"]) c.Locals("email", (*claims)["email"]) return c.Next() } }