Authsome

Bridges

Optional integration adapters that connect Authsome to the broader Forgery ecosystem.

Bridges are Authsome's extension point for optional third-party and Forgery ecosystem integrations. Each bridge is a thin Go interface defined in the github.com/xraph/authsome/bridge package. You implement the interface yourself, use one of the provided adapter packages, or use the built-in no-op stubs for local development.

When a bridge is not configured, Authsome uses a sensible default: audit events go to slog, webhook delivery is dropped with a debug log, emails are logged and discarded. Your application always starts and runs — bridges are opt-in enhancements, not requirements.

The bridge pattern

Each bridge follows the same pattern:

  1. Interface — defined in github.com/xraph/authsome/bridge. Narrow by design (1–4 methods).
  2. Adapter package — a thin translation layer in github.com/xraph/authsome/bridge/<name>adapter that wraps the real extension client.
  3. Stub — a no-op implementation in bridge/stubs.go used as a fallback when the bridge is not configured.
  4. Option — a With* function on the engine for registering the bridge.
authsome/
├── bridge/
│   ├── chronicle.go       ← Chronicle interface + AuditEvent type
│   ├── relay.go           ← EventRelay interface + WebhookEvent type
│   ├── herald.go          ← Herald interface
│   ├── vault.go           ← Vault interface
│   ├── dispatch.go        ← Dispatcher interface
│   ├── ledger.go          ← Ledger interface
│   ├── warden.go          ← Authorizer interface
│   ├── keysmith.go        ← KeyManager interface
│   ├── mailer.go          ← Mailer interface
│   ├── sms.go             ← SMSSender interface
│   ├── metrics.go         ← MetricsCollector interface
│   └── stubs.go           ← No-op implementations for all bridges
└── bridge/
    ├── chronicleadapter/  ← Wraps *chronicle.Engine
    ├── relayadapter/      ← Wraps *relay.Engine
    ├── heraldadapter/     ← Wraps *herald.Engine
    ├── vaultadapter/      ← Wraps *vault.Vault
    ├── dispatchadapter/   ← Wraps *dispatch.Engine
    ├── ledgeradapter/     ← Wraps *ledger.Engine
    ├── wardenadapter/     ← Wraps *warden.Engine
    ├── keysmithadapter/   ← Wraps *keysmith.Engine
    ├── maileradapter/     ← Wraps email providers
    └── smsadapter/        ← Wraps SMS providers

Available bridges

BridgeOptionInterfaceWhat it does
ChronicleWithChroniclebridge.ChronicleRecords all auth events to an audit trail
RelayWithEventRelaybridge.EventRelayDelivers webhook payloads to subscribers
HeraldWithHeraldbridge.HeraldMulti-channel notifications (email, SMS, push)
VaultWithVaultbridge.VaultSecrets management and feature flags
DispatchWithDispatcherbridge.DispatcherBackground job queue for async tasks
LedgerWithLedgerbridge.LedgerBilling metering and entitlement checks
WardenWithWarden / WithAuthorizerbridge.AuthorizerAdvanced RBAC and policy evaluation
KeysmithWithKeysmith / WithKeyManagerbridge.KeyManagerCentralized API key management
MailerWithMailerbridge.MailerTransactional email delivery
SMSWithSMSSenderbridge.SMSSenderSMS delivery for OTP and MFA codes
MetricsWithMetricsbridge.MetricsCollectorObservability metrics export

Registering bridges

Bridges are registered using the corresponding With* option when constructing the engine:

import (
    "github.com/xraph/authsome"
    "github.com/xraph/authsome/bridge/chronicleadapter"
    "github.com/xraph/authsome/bridge/relayadapter"
    "github.com/xraph/authsome/bridge/maileradapter"
)

eng, err := authsome.New(
    authsome.WithStore(pgStore),
    authsome.WithPlugin(password.New()),

    // Chronicle: audit all auth events.
    authsome.WithChronicle(chronicleadapter.New(chronicleClient)),

    // Relay: deliver webhook events reliably.
    authsome.WithEventRelay(relayadapter.New(relayClient)),

    // Mailer: send verification and reset emails.
    authsome.WithMailer(maileradapter.NewResend(os.Getenv("RESEND_API_KEY"))),
)

Using the Forgery first-class bridge options

For Warden and Keysmith, Authsome provides dedicated With* options that accept the concrete extension engine directly — you do not need to import the adapter package separately:

import (
    "github.com/xraph/warden"
    "github.com/xraph/keysmith"
)

wardenEng, _ := warden.New(...)
keysmithEng, _ := keysmith.New(...)

eng, err := authsome.New(
    authsome.WithStore(pgStore),
    // WithWarden accepts *warden.Engine directly.
    authsome.WithWarden(wardenEng),
    // WithKeysmith accepts *keysmith.Engine directly.
    authsome.WithKeysmith(keysmithEng),
)

Both options internally wrap the engine in the appropriate adapter package and also set the bridge.Authorizer / bridge.KeyManager for backward compatibility.

No-op stubs for development

When developing locally without the full Forgery stack, you can use the built-in stubs:

import "github.com/xraph/authsome/bridge"

eng, err := authsome.New(
    authsome.WithStore(memory.New()),
    // Log audit events to slog instead of Chronicle.
    authsome.WithChronicle(bridge.NewSlogChronicle(slog.Default())),
    // Drop webhook events silently.
    authsome.WithEventRelay(bridge.NewNoopRelay(slog.Default())),
    // Log emails to debug instead of sending them.
    authsome.WithMailer(bridge.NewNoopMailer(slog.Default())),
)

Custom bridge implementations

You can implement any bridge interface directly if you want to integrate with a system that does not have a Forgery adapter:

// Custom Mailer using SendGrid.
type SendGridMailer struct {
    client *sendgrid.Client
    from   string
}

func (m *SendGridMailer) SendEmail(ctx context.Context, msg *bridge.EmailMessage) error {
    message := mail.NewSingleEmail(
        mail.NewEmail("", m.from),
        msg.Subject,
        mail.NewEmail("", msg.To[0]),
        msg.Text,
        msg.HTML,
    )
    _, err := m.client.SendWithContext(ctx, message)
    return err
}

// Register with the engine.
eng, err := authsome.New(
    authsome.WithStore(pgStore),
    authsome.WithMailer(&SendGridMailer{
        client: sendgrid.NewSendClient(os.Getenv("SENDGRID_API_KEY")),
        from:   "noreply@myapp.com",
    }),
)

Where to go next

On this page