package middleware import ( "net/http" "strings" "attune-heart-therapy/internal/services" "github.com/gin-gonic/gin" ) // AuthMiddleware creates a middleware for JWT authentication func AuthMiddleware(jwtService services.JWTService) gin.HandlerFunc { return func(c *gin.Context) { // Get token from Authorization header authHeader := c.GetHeader("Authorization") if authHeader == "" { c.JSON(http.StatusUnauthorized, gin.H{ "error": "Authorization header is required", }) c.Abort() return } // Check if header starts with "Bearer " tokenParts := strings.SplitN(authHeader, " ", 2) if len(tokenParts) != 2 || tokenParts[0] != "Bearer" { c.JSON(http.StatusUnauthorized, gin.H{ "error": "Invalid authorization header format. Expected: Bearer ", }) c.Abort() return } tokenString := tokenParts[1] if tokenString == "" { c.JSON(http.StatusUnauthorized, gin.H{ "error": "Token is required", }) c.Abort() return } // Validate the token claims, err := jwtService.ValidateToken(tokenString) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{ "error": "Invalid or expired token", }) c.Abort() return } // Set user information in context for use in handlers c.Set("user_id", claims.UserID) c.Set("user_email", claims.Email) c.Set("is_admin", claims.IsAdmin) c.Set("jwt_claims", claims) c.Next() } } // GetUserIDFromContext extracts user ID from Gin context func GetUserIDFromContext(c *gin.Context) (uint, bool) { userID, exists := c.Get("user_id") if !exists { return 0, false } id, ok := userID.(uint) return id, ok } // GetUserEmailFromContext extracts user email from Gin context func GetUserEmailFromContext(c *gin.Context) (string, bool) { email, exists := c.Get("user_email") if !exists { return "", false } emailStr, ok := email.(string) return emailStr, ok } // IsAdminFromContext checks if user is admin from Gin context func IsAdminFromContext(c *gin.Context) bool { isAdmin, exists := c.Get("is_admin") if !exists { return false } admin, ok := isAdmin.(bool) return ok && admin } // GetJWTClaimsFromContext extracts JWT claims from Gin context func GetJWTClaimsFromContext(c *gin.Context) (*services.JWTClaims, bool) { claims, exists := c.Get("jwt_claims") if !exists { return nil, false } jwtClaims, ok := claims.(*services.JWTClaims) return jwtClaims, ok } // AdminMiddleware creates a middleware for admin authorization // This middleware should be used after AuthMiddleware to ensure user is authenticated first func AdminMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // Check if user is authenticated (should be set by AuthMiddleware) userID, exists := GetUserIDFromContext(c) if !exists || userID == 0 { c.JSON(http.StatusUnauthorized, gin.H{ "error": "Authentication required", }) c.Abort() return } // Check if user has admin privileges if !IsAdminFromContext(c) { c.JSON(http.StatusForbidden, gin.H{ "error": "Admin privileges required", }) c.Abort() return } c.Next() } } // RequireAdmin is a convenience function that combines auth and admin middleware func RequireAdmin(jwtService services.JWTService) gin.HandlerFunc { return gin.HandlerFunc(func(c *gin.Context) { // First authenticate the user AuthMiddleware(jwtService)(c) if c.IsAborted() { return } // Then check admin privileges AdminMiddleware()(c) }) }