package middleware import ( "bugulma/backend/internal/service" "context" "log" "strings" "github.com/gin-gonic/gin" ) // Context keys for storing user/org info type contextKey string const ( UserIDKey contextKey = "user_id" OrgIDKey contextKey = "org_id" ) // ContextMiddleware extracts user and organization information from headers/tokens func ContextMiddleware(authService *service.AuthService) gin.HandlerFunc { return func(c *gin.Context) { // Try to extract user ID from JWT token userID, orgID := extractFromJWT(c, authService) if userID != "" { ctx := context.WithValue(c.Request.Context(), UserIDKey, userID) c.Request = c.Request.WithContext(ctx) // Also set in Gin context for handlers that use c.Get() c.Set("user_id", userID) } if orgID != "" { ctx := context.WithValue(c.Request.Context(), OrgIDKey, orgID) c.Request = c.Request.WithContext(ctx) // Also set in Gin context for handlers that use c.Get() c.Set("org_id", orgID) } // Fallback to headers/query params for development if userID == "" { userID = extractUserID(c) if userID != "" { ctx := context.WithValue(c.Request.Context(), UserIDKey, userID) c.Request = c.Request.WithContext(ctx) // Also set in Gin context for handlers that use c.Get() c.Set("user_id", userID) } } if orgID == "" { orgID = extractOrgID(c) if orgID != "" { ctx := context.WithValue(c.Request.Context(), OrgIDKey, orgID) c.Request = c.Request.WithContext(ctx) // Also set in Gin context for handlers that use c.Get() c.Set("org_id", orgID) } } c.Next() } } // extractFromJWT extracts user and organization info from JWT token func extractFromJWT(c *gin.Context, authService *service.AuthService) (string, string) { authHeader := c.GetHeader("Authorization") if !strings.HasPrefix(authHeader, "Bearer ") { return "", "" } tokenString := strings.TrimPrefix(authHeader, "Bearer ") if tokenString == "" { return "", "" } // Validate token and extract claims _, claims, err := authService.ValidateTokenWithClaims(c.Request.Context(), tokenString) if err != nil { log.Printf("JWT validation failed: %v", err) return "", "" } return claims.UserID, claims.OrgID } // extractUserID extracts user ID from request (fallback for development) func extractUserID(c *gin.Context) string { // Check query parameter (for development/testing) if userID := c.Query("user_id"); userID != "" { return userID } // Default fallback return "system" } // extractOrgID extracts organization ID from request func extractOrgID(c *gin.Context) string { // Check X-Organization-ID header if orgID := c.GetHeader("X-Organization-ID"); orgID != "" { return orgID } // Check query parameter (for development/testing) if orgID := c.Query("org_id"); orgID != "" { return orgID } // For resource flow operations, we might need to determine org from path params // This would be handled in the service layer based on the entity being operated on return "" } // GetUserIDFromContext extracts user ID from context func GetUserIDFromContext(ctx context.Context) string { if userID, ok := ctx.Value(UserIDKey).(string); ok { return userID } return "system" } // GetOrgIDFromContext extracts organization ID from context func GetOrgIDFromContext(ctx context.Context) string { if orgID, ok := ctx.Value(OrgIDKey).(string); ok { return orgID } return "" }