package middleware import ( "net/http" "veza-backend-api/internal/models" "veza-backend-api/internal/services" "github.com/gin-gonic/gin" ) // RequireAPIKeyScope returns a Gin middleware that enforces API key scopes. // For API key authenticated requests, it verifies the key has the required scope. // JWT-authenticated requests pass through (they already use RBAC). // // Scope mapping: // - GET/HEAD/OPTIONS → "read" // - POST/PUT/PATCH/DELETE → "write" // - "admin" scope implies both "read" and "write" func RequireAPIKeyScope(apiKeyService *services.APIKeyService) gin.HandlerFunc { return func(c *gin.Context) { apiKeyVal, exists := c.Get("api_key") if !exists { // Not an API key request (JWT auth) — pass through c.Next() return } key, ok := apiKeyVal.(*models.APIKey) if !ok { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": gin.H{ "code": "INTERNAL_ERROR", "message": "Invalid API key context", }, }) c.Abort() return } var requiredScope string switch c.Request.Method { case http.MethodGet, http.MethodHead, http.MethodOptions: requiredScope = "read" default: requiredScope = "write" } if !apiKeyService.HasScope(key, requiredScope) { c.JSON(http.StatusForbidden, gin.H{ "success": false, "error": gin.H{ "code": "INSUFFICIENT_SCOPE", "message": "API key does not have the required scope: " + requiredScope, "required_scope": requiredScope, "key_scopes": key.Scopes, }, }) c.Abort() return } c.Next() } }