sphinx-tribes
sphinx-tribes copied to clipboard
endPoint authentication confirm token header (env.SWWF_RESKEY)
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:
- Is there a token in the header?
- Is our expected token set in the environment?
- 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 assign me?
@humansinstitute, please assign me?
@tobi-bams will discuss later. Just want to walk through this design