Keysmith

Architecture

How Keysmith's packages fit together.

Keysmith is organized as a set of focused Go packages. The root keysmith package provides the engine, types, hasher, and key generator. Five subsystem packages define domain entities and store interfaces. Supporting packages provide plugins, middleware, API handlers, and the Forge extension adapter. Two store backends implement the same composite interface.

Package diagram

┌─────────────────────────────────────────────────────────────────────────┐
│                          keysmith.Engine                                │
│                                                                         │
│  CreateKey   ValidateKey   RotateKey   RevokeKey   SuspendKey          │
│  ReactivateKey   GetKey   ListKeys                                     │
│  CreatePolicy  UpdatePolicy  DeletePolicy  ListPolicies                │
│  AssignScopes  RemoveScopes  RecordUsage  GetUsageAggregation         │
├──────────────────────────┬──────────────────────────────────────────────┤
│   Supporting packages    │   Plugin system                              │
│                          │                                              │
│  Hasher (SHA-256)       │  plugin.Plugin (base)                       │
│  KeyGenerator           │  plugin.Manager                              │
│  id     (TypeID)         │    KeyCreated / KeyRevoked                   │
│  scope  (context keys)   │    KeyRotated / KeySuspended                 │
│  api    (REST handlers)  │    KeyValidated / KeyExpired                 │
│  middleware (auth)       │    PolicyCreated / PolicyUpdated             │
│  extension (Forge)       │    KeyRateLimited / Shutdown                 │
│                          │                                              │
│  audit_hook (audit)      │  observability (metrics)                    │
│  warden_hook (authz)     │                                              │
├──────────────────────────┴──────────────────────────────────────────────┤
│                           store.Store                                   │
│  (composite: key.Store + policy.Store + scope.Store +                  │
│   usage.Store + rotation.Store + Migrate / Ping / Close)               │
├───────────────────────────────────────┬─────────────────────────────────┤
│ store/memory                          │ store/postgres                  │
│ (in-process maps + sync.RWMutex)     │ (pgx connection pool)          │
└───────────────────────────────────────┴─────────────────────────────────┘

Engine construction

The engine is the central coordinator. Configure it with functional options.

import (
    "github.com/xraph/keysmith"
    "github.com/xraph/keysmith/store/memory"
    audithook "github.com/xraph/keysmith/audit_hook"
    "github.com/xraph/keysmith/observability"
)

eng, err := keysmith.NewEngine(
    keysmith.WithStore(memory.New()),
    keysmith.WithExtension(audithook.New(myRecorder)),
    keysmith.WithExtension(observability.NewMetricsExtension()),
)

Request flow

Every Keysmith operation follows the same three-phase flow: scope, resolve, respond.

1. Scope

The engine extracts app ID and tenant ID from the context. In standalone mode, use keysmith.WithTenant. With Forge, scope is extracted automatically from forge.Scope.

ctx := keysmith.WithTenant(ctx, "my-app", "tenant-1")

2. Resolve

Each operation resolves the requested resource using scope values from context:

  • CreateKey -- generates a raw key, hashes it with SHA-256, stores the hash, fires KeyCreated hooks
  • ValidateKey -- hashes the incoming raw key, looks up the hash in the store, checks state, checks policy, fires KeyValidated or KeyValidationFailed
  • RotateKey -- creates a new key, marks old key as rotated, records grace period, fires KeyRotated
  • RevokeKey -- transitions key to revoked state, fires KeyRevoked

3. Respond

The result is returned to the caller. For validation, this includes the key entity, scopes, and policy information. For creation, it includes the raw key (shown once) and the key metadata.

Key states

active → rotated → revoked
active → suspended → active (reactivate)
active → expired
active → revoked

Tenant isolation

Keysmith enforces tenant isolation at multiple layers:

LayerMechanism
Contextkeysmith.WithTenant injects app ID and tenant ID into context.Context
EngineEvery operation reads scope from context before querying the store
StoreAll queries include app ID and tenant ID as scoping parameters
ValidationKey validation verifies the key belongs to the requesting tenant
Plugin hooksLifecycle events include tenant context for audit and metrics

Plugin system

The plugin.Manager uses type assertion to discover which lifecycle hooks each plugin implements.

import "github.com/xraph/keysmith/plugin"

// A plugin implements plugin.Plugin (Name) and any combination of hooks.
type myPlugin struct{}
func (p *myPlugin) Name() string { return "my-plugin" }
func (p *myPlugin) OnKeyCreated(ctx context.Context, k *key.Key) error { ... }
func (p *myPlugin) OnKeyRevoked(ctx context.Context, k *key.Key, reason string) error { ... }

Lifecycle hooks

InterfaceMethodFired when
KeyCreatedOnKeyCreated(ctx, key)Key successfully created
KeyCreateFailedOnKeyCreateFailed(ctx, key, err)Key creation fails
KeyValidatedOnKeyValidated(ctx, key)Key passes validation
KeyValidationFailedOnKeyValidationFailed(ctx, rawKey, err)Key validation fails
KeyRotatedOnKeyRotated(ctx, key, record)Key is rotated
KeyRevokedOnKeyRevoked(ctx, key, reason)Key is permanently revoked
KeySuspendedOnKeySuspended(ctx, key)Key is temporarily suspended
KeyReactivatedOnKeyReactivated(ctx, key)Suspended key is reactivated
KeyExpiredOnKeyExpired(ctx, key)Key found expired during validation
KeyRateLimitedOnKeyRateLimited(ctx, key)Key exceeds rate limit
PolicyCreatedOnPolicyCreated(ctx, policy)Policy created
PolicyUpdatedOnPolicyUpdated(ctx, policy)Policy updated
PolicyDeletedOnPolicyDeleted(ctx, policyID)Policy deleted
ShutdownOnShutdown(ctx)Engine shutting down

Package index

PackageImport pathPurpose
keysmithgithub.com/xraph/keysmithCore engine, types, hasher, generator
keygithub.com/xraph/keysmith/keyKey entity, lifecycle states, store interface
policygithub.com/xraph/keysmith/policyPolicy entity, store interface
scopegithub.com/xraph/keysmith/scopeScope entity, key-scope assignment, store interface
usagegithub.com/xraph/keysmith/usageUsage records, aggregation, store interface
rotationgithub.com/xraph/keysmith/rotationRotation records, reasons, store interface
idgithub.com/xraph/keysmith/idTypeID-based entity identifiers (akey, kpol, kusg, krot, kscp)
storegithub.com/xraph/keysmith/storeComposite store interface embedding all sub-stores
store/memorygithub.com/xraph/keysmith/store/memoryIn-memory store for testing
store/postgresgithub.com/xraph/keysmith/store/postgresPostgreSQL store with embedded migrations
plugingithub.com/xraph/keysmith/pluginLifecycle hook interfaces and dispatch manager
audit_hookgithub.com/xraph/keysmith/audit_hookAudit trail plugin
observabilitygithub.com/xraph/keysmith/observabilityMetrics plugin (go-utils counters)
warden_hookgithub.com/xraph/keysmith/warden_hookWarden authorization bridge plugin
apigithub.com/xraph/keysmith/apiForge-style REST API handlers
middlewaregithub.com/xraph/keysmith/middlewareHTTP middleware for API key validation
extensiongithub.com/xraph/keysmith/extensionForge extension adapter (DI, routes, migration)

On this page