Plugin System
Opt-in lifecycle hooks for audit, metrics, and authorization.
Keysmith uses an opt-in plugin system. Plugins implement plugin.Plugin (which requires only Name()) and any combination of lifecycle hooks. The plugin.Manager discovers capabilities via type assertion at registration time.
Registering plugins
eng, _ := keysmith.NewEngine(
keysmith.WithStore(store),
keysmith.WithExtension(audithook.New(myRecorder)),
keysmith.WithExtension(observability.NewMetricsExtension()),
keysmith.WithExtension(wardenhook.New(bridge)),
)Writing a custom plugin
A plugin is any type that implements plugin.Plugin and one or more hook interfaces:
import (
"context"
"github.com/xraph/keysmith/plugin"
"github.com/xraph/keysmith/key"
)
type SlackNotifier struct {
webhookURL string
}
func (s *SlackNotifier) Name() string { return "slack-notifier" }
func (s *SlackNotifier) OnKeyCreated(ctx context.Context, k *key.Key) error {
return postToSlack(s.webhookURL, fmt.Sprintf("New API key created: %s", k.Name))
}
func (s *SlackNotifier) OnKeyRevoked(ctx context.Context, k *key.Key, reason string) error {
return postToSlack(s.webhookURL, fmt.Sprintf("API key revoked: %s (reason: %s)", k.Name, reason))
}Available hooks
| Hook | Interface | Signature |
|---|---|---|
| Key created | plugin.KeyCreated | OnKeyCreated(ctx, *key.Key) error |
| Key creation failed | plugin.KeyCreateFailed | OnKeyCreateFailed(ctx, *key.Key, error) error |
| Key validated | plugin.KeyValidated | OnKeyValidated(ctx, *key.Key) error |
| Key validation failed | plugin.KeyValidationFailed | OnKeyValidationFailed(ctx, string, error) error |
| Key rotated | plugin.KeyRotated | OnKeyRotated(ctx, *key.Key, *rotation.Record) error |
| Key revoked | plugin.KeyRevoked | OnKeyRevoked(ctx, *key.Key, string) error |
| Key suspended | plugin.KeySuspended | OnKeySuspended(ctx, *key.Key) error |
| Key reactivated | plugin.KeyReactivated | OnKeyReactivated(ctx, *key.Key) error |
| Key expired | plugin.KeyExpired | OnKeyExpired(ctx, *key.Key) error |
| Key rate limited | plugin.KeyRateLimited | OnKeyRateLimited(ctx, *key.Key) error |
| Policy created | plugin.PolicyCreated | OnPolicyCreated(ctx, *policy.Policy) error |
| Policy updated | plugin.PolicyUpdated | OnPolicyUpdated(ctx, *policy.Policy) error |
| Policy deleted | plugin.PolicyDeleted | OnPolicyDeleted(ctx, id.PolicyID) error |
| Shutdown | plugin.Shutdown | OnShutdown(ctx) error |
Built-in plugins
Audit Hook
Emits structured audit events to a Recorder backend for every lifecycle event.
import audithook "github.com/xraph/keysmith/audit_hook"
recorder := audithook.RecorderFunc(func(ctx context.Context, evt *audithook.AuditEvent) error {
log.Printf("[%s] %s %s: %s", evt.Severity, evt.Action, evt.ResourceID, evt.Outcome)
return nil
})
eng, _ := keysmith.NewEngine(
keysmith.WithStore(store),
keysmith.WithExtension(audithook.New(recorder)),
)Observability Metrics
Increments go-utils metric counters for each lifecycle event.
import "github.com/xraph/keysmith/observability"
eng, _ := keysmith.NewEngine(
keysmith.WithStore(store),
keysmith.WithExtension(observability.NewMetricsExtension()),
)Warden Hook
Bridges Keysmith key lifecycle events to Warden authorization. Syncs scopes as Warden permissions and assigns roles to API key subjects.
import wardenhook "github.com/xraph/keysmith/warden_hook"
eng, _ := keysmith.NewEngine(
keysmith.WithStore(store),
keysmith.WithExtension(wardenhook.New(wardenBridge,
wardenhook.WithDefaultRole("api-consumer"),
)),
)