SecureWebhookToken is an Internet-Draft for sending secure Webhooks, based on the JWT standard. See Documentation for more details.
go get github.com/SecureWebhookToken/swt
package main
import (
"fmt"
"log/slog"
"net/http"
"github.com/SecureWebhookToken/swt"
)
const (
issuer = "https://example.com"
url = "http://localhost:8080/webhook"
)
// WARNING: This is a weak secret for demonstration purposes only!
// In production, use a strong, randomly generated secret key.
// Generate one with: openssl rand -base64 32
var secretKey = []byte("INSECURE-EXAMPLE-SECRET-DO-NOT-USE-IN-PRODUCTION")
func main() {
go startServer()
// Valid webhook request
swtReq := swt.Request{
URL: url,
Issuer: issuer,
Event: "send.stars",
Data: []byte(`{"username": "me", "stars": "567"}`),
}
req, err := swtReq.Build(secretKey)
if err != nil {
slog.Error(fmt.Errorf("error building request: %w", err).Error())
return
}
httpClient := &http.Client{}
res, err := httpClient.Do(req)
if err != nil {
slog.Error("Error executing request", "error", err)
return
}
slog.Info("Successfully executed request", "status", res.StatusCode)
// Invalid issuer webhook request
swtReq = swt.Request{
URL: url,
Issuer: "issuer",
Event: "send.stars",
Data: []byte(`{"username": "me", "stars": "567"}`),
}
req, err = swtReq.Build(secretKey)
if err != nil {
slog.Error(fmt.Errorf("error building request: %w", err).Error())
return
}
httpClient = &http.Client{}
res, err = httpClient.Do(req)
if err != nil {
slog.Error("Error executing request", "error", err)
return
}
slog.Info("Successfully executed request", "status", res.StatusCode)
}
func startServer() {
handler, err := swt.NewHandlerFunc(secretKey, func(token *swt.SecureWebhookToken, data []byte) error {
slog.Info("Successfully received token: " + token.String())
//Validate issuer
if token.Issuer() != issuer {
return fmt.Errorf("invalid issuer")
}
slog.Info("Successfully received webhook data: " + string(data))
return nil
}, nil)
if err != nil {
slog.Error("Failed to create handler", "error", err)
return
}
http.Handle("/webhook", handler)
slog.Error("Server error", "error", http.ListenAndServe(":8080", nil))
}