sphinx-tribes icon indicating copy to clipboard operation
sphinx-tribes copied to clipboard

endPoint authentication confirm token header (env.SWWF_RESKEY)

Open humansinstitute opened this issue 1 year ago • 3 comments

For context see: https://github.com/stakwork/sphinx-tribes/issues/1922

Blockers:

  • https://github.com/stakwork/sphinx-tribes/issues/1929
  • https://github.com/stakwork/sphinx-tribes/issues/1927

Update to check Token in Header of response from Stakwork includes SWWF_RESKEY

Logic

Every time a request comes to /workflow/response, a ValidateStakworkToken function runs first It checks three things:

  1. Is there a token in the header?
  2. Is our expected token set in the environment?
  3. Do the tokens match?

If anything is wrong, it returns an error and stops

Missing token: 401 error
Server not configured: 500 error
Wrong token: 401 error

If the token is correct, it lets the request continue to the actual handler

Example test:

# Wrong - No token
curl -X POST http://your-server/workflow/response

# Wrong - Invalid token
curl -X POST \
  -H "X-Stakwork-Token: wrong-token" \
  http://your-server/workflow/response

# Correct
curl -X POST \
  -H "X-Stakwork-Token: your-actual-token" \
  http://your-server/workflow/response

Example Token Handler:

// Simple Version
func ValidateStakworkToken(c *fiber.Ctx) error {
    // Get token from header
    token := c.Get("X-Stakwork-Token")
    
    // Get environment variable
    expectedToken := os.Getenv("SWWF_RESKEY")
    
    // Compare tokens
    if token != expectedToken {
        return c.Status(401).JSON(fiber.Map{
            "error": "invalid token",
        })
    }
    
    // Continue to next handler if token is valid
    return c.Next()
}

// More Complete Version
func ValidateStakworkToken(logger *zap.Logger) fiber.Handler {
    return func(c *fiber.Ctx) error {
        // Get token from header
        token := c.Get("X-Stakwork-Token")
        
        // Check if token is present
        if token == "" {
            logger.Warn("missing authentication token")
            return c.Status(401).JSON(fiber.Map{
                "error": "missing authentication token",
                "code":  "MISSING_TOKEN",
            })
        }
        
        // Get expected token from environment
        expectedToken := os.Getenv("SWWF_RESKEY")
        if expectedToken == "" {
            logger.Error("SWWF_RESKEY not set in environment")
            return c.Status(500).JSON(fiber.Map{
                "error": "server configuration error",
                "code":  "SERVER_ERROR",
            })
        }
        
        // Compare tokens using secure comparison
        if !hmac.Equal([]byte(token), []byte(expectedToken)) {
            logger.Warn("invalid token provided",
                zap.String("ip", c.IP()),
                zap.String("path", c.Path()))
            return c.Status(401).JSON(fiber.Map{
                "error": "invalid authentication token",
                "code":  "INVALID_TOKEN",
            })
        }
        
        // Token is valid, continue
        return c.Next()
    }
}

// Usage in your main.go or routes setup
func SetupRoutes(app *fiber.App, logger *zap.Logger) {
    // Create a group for workflow endpoints
    workflow := app.Group("/workflow")
    
    // Add the token validation middleware to the response endpoint
    workflow.Post("/response",
        ValidateStakworkToken(logger),  // Validate token first
        HandleWorkflowResponse,         // Then handle the response
    )
}

// Example handler for workflow response
func HandleWorkflowResponse(c *fiber.Ctx) error {
    // Parse the response body
    var response struct {
        RequestUUID string          `json:"request_uuid"`
        Response    string          `json:"response"`
        Data       json.RawMessage `json:"data"`
    }
    
    if err := c.BodyParser(&response); err != nil {
        return c.Status(400).JSON(fiber.Map{
            "error": "invalid request body",
            "code":  "INVALID_BODY",
        })
    }
    
    // Process the workflow response...
    
    return c.Status(200).JSON(fiber.Map{
        "status": "success",
    })
}

humansinstitute avatar Nov 11 '24 02:11 humansinstitute

@humansinstitute assign me?

MirzaHanan avatar Nov 11 '24 02:11 MirzaHanan

@humansinstitute, please assign me?

aliraza556 avatar Nov 11 '24 02:11 aliraza556

@tobi-bams will discuss later. Just want to walk through this design

humansinstitute avatar Nov 11 '24 05:11 humansinstitute