Authsome

Metrics Bridge

Observability integration — emits authentication metrics to Prometheus, OpenTelemetry, or any collector backend.

The Metrics bridge connects Authsome to your observability stack. When configured, Authsome emits metrics for every authentication event: event counts by action and outcome, sign-in latency, session counts, active user gauges, and more. The bridge is a thin interface — you wire it to Prometheus, OpenTelemetry, Datadog, or any other metrics backend.

Interface

The bridge.MetricsCollector interface is defined in github.com/xraph/authsome/bridge:

type MetricsCollector interface {
    RecordEvent(action, resource, outcome, tenant string, duration time.Duration)
    IncrementGauge(name, tenant string, delta int)
}

RecordEvent

Called after every authentication operation:

ParameterTypeDescription
actionstringOperation name, e.g. "auth.signin", "auth.signup", "session.refresh"
resourcestringEntity type affected, e.g. "session", "user", "mfa"
outcomestring"success" or "failure"
tenantstringOrganisation ID or empty string for no-org context
durationtime.DurationWall-clock time of the operation

IncrementGauge

Called to adjust live gauges (e.g., active session count):

ParameterTypeDescription
namestringGauge name, e.g. "active_sessions", "registered_users"
tenantstringOrganisation ID for per-tenant gauges
deltaint+1 to increment, -1 to decrement

Setup with a Prometheus adapter

import (
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promauto"
    "github.com/xraph/authsome"
    "github.com/xraph/authsome/bridge"
    "time"
)

// Prometheus-backed MetricsCollector.
type PrometheusCollector struct {
    eventCounter *prometheus.CounterVec
    latencyHist  *prometheus.HistogramVec
    gauges       *prometheus.GaugeVec
}

func NewPrometheusCollector(reg prometheus.Registerer) *PrometheusCollector {
    return &PrometheusCollector{
        eventCounter: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{
            Name: "authsome_events_total",
            Help: "Total auth events by action, resource, outcome, and tenant.",
        }, []string{"action", "resource", "outcome", "tenant"}),

        latencyHist: promauto.With(reg).NewHistogramVec(prometheus.HistogramOpts{
            Name:    "authsome_event_duration_seconds",
            Help:    "Auth event duration distribution.",
            Buckets: prometheus.DefBuckets,
        }, []string{"action", "resource", "outcome"}),

        gauges: promauto.With(reg).NewGaugeVec(prometheus.GaugeOpts{
            Name: "authsome_gauge",
            Help: "Live auth metrics gauges.",
        }, []string{"name", "tenant"}),
    }
}

func (c *PrometheusCollector) RecordEvent(action, resource, outcome, tenant string, duration time.Duration) {
    c.eventCounter.WithLabelValues(action, resource, outcome, tenant).Inc()
    c.latencyHist.WithLabelValues(action, resource, outcome).Observe(duration.Seconds())
}

func (c *PrometheusCollector) IncrementGauge(name, tenant string, delta int) {
    c.gauges.WithLabelValues(name, tenant).Add(float64(delta))
}

// Register with Authsome.
eng, err := authsome.New(
    authsome.WithStore(pgStore),
    authsome.WithMetrics(NewPrometheusCollector(prometheus.DefaultRegisterer)),
)

Setup with an OpenTelemetry adapter

import (
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/metric"
)

type OTelCollector struct {
    meter    metric.Meter
    counter  metric.Int64Counter
    latency  metric.Float64Histogram
    gauges   map[string]metric.Int64UpDownCounter
    mu       sync.Mutex
}

func NewOTelCollector() (*OTelCollector, error) {
    meter := otel.GetMeterProvider().Meter("authsome")

    counter, err := meter.Int64Counter("authsome.events.total",
        metric.WithDescription("Total auth events"))
    if err != nil {
        return nil, err
    }

    latency, err := meter.Float64Histogram("authsome.event.duration",
        metric.WithUnit("s"),
        metric.WithDescription("Auth event duration"))
    if err != nil {
        return nil, err
    }

    return &OTelCollector{meter: meter, counter: counter, latency: latency,
        gauges: make(map[string]metric.Int64UpDownCounter)}, nil
}

func (c *OTelCollector) RecordEvent(action, resource, outcome, tenant string, duration time.Duration) {
    attrs := metric.WithAttributes(
        attribute.String("action", action),
        attribute.String("resource", resource),
        attribute.String("outcome", outcome),
        attribute.String("tenant", tenant),
    )
    c.counter.Add(context.Background(), 1, attrs)
    c.latency.Record(context.Background(), duration.Seconds(), attrs)
}

func (c *OTelCollector) IncrementGauge(name, tenant string, delta int) {
    // Acquire or create the gauge for this name.
    // ...
}

Metrics emitted by Authsome

The following events and gauges are emitted when the Metrics bridge is configured:

Events (RecordEvent)

ActionResourceWhen
auth.signupuserUser successfully registered
auth.signinsessionSign-in completed (success or failure)
auth.signoutsessionUser signed out
auth.refreshsessionSession token refreshed
auth.mfa.enrolledmfaMFA method enrolled
auth.mfa.verifiedmfaMFA challenge completed
auth.passkey.authenticatedpasskeyPasskey login completed
auth.social.signinsessionSocial OAuth sign-in completed
auth.password.resetaccountPassword reset flow completed
apikey.validatedapikeyAPI key validated
session.revokedsessionSession explicitly revoked

Gauges (IncrementGauge)

NameWhen incrementedWhen decremented
active_sessionsSession createdSession expired or revoked
registered_usersUser createdUser deleted
mfa_enrolled_usersMFA enrolledMFA disabled

When no metrics bridge is configured

Without a metrics bridge, Authsome performs all operations normally. No metrics overhead is incurred — the bridge check is a single nil pointer check. Configuring metrics is purely additive.

On this page