instrumentation

package
v0.2.113 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 28, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package instrumentation provides OpenTelemetry (OTEL) instrumentation for the mcp-oauth library.

This package enables comprehensive observability across all library layers through: - Metrics: Counters, histograms, and gauges for monitoring OAuth operations - Traces: Distributed tracing for request flows across components - Logging: Structured logs with trace context integration

Quick Start

Enable basic instrumentation with stdout exporters (development):

import "github.com/giantswarm/mcp-oauth/instrumentation"

// Initialize instrumentation
inst, err := instrumentation.New(instrumentation.Config{
	ServiceName:     "my-oauth-service",
	ServiceVersion:  "1.0.0",
	MetricsExporter: "stdout",  // Print metrics to stdout
	TracesExporter:  "stdout",  // Print traces to stdout
})
if err != nil {
	log.Fatal(err)
}
defer inst.Shutdown(context.Background())

// Pass to server configuration
server.SetInstrumentation(inst)

Exporter Configuration

The library supports multiple exporters for metrics and traces:

Metrics Exporters:

  • "prometheus": Export metrics in Prometheus format (production recommended)
  • "stdout": Print metrics to stdout (development/debugging)
  • "none" or "": No metrics export (default, zero overhead)

Trace Exporters:

  • "otlp": Export traces via OTLP HTTP (production recommended, requires OTLPEndpoint)
  • "stdout": Print traces to stdout (development/debugging)
  • "none" or "": No trace export (default, zero overhead)

Prometheus Metrics (Production)

Export metrics to Prometheus:

import (
	"github.com/giantswarm/mcp-oauth/instrumentation"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

inst, err := instrumentation.New(instrumentation.Config{
	ServiceName:     "my-oauth-service",
	ServiceVersion:  "1.0.0",
	MetricsExporter: "prometheus",
})
if err != nil {
	log.Fatal(err)
}

// Expose /metrics endpoint for Prometheus to scrape
http.Handle("/metrics", promhttp.Handler())

OTLP Traces (Production)

Export traces to Jaeger, Grafana Tempo, or any OTLP-compatible backend:

inst, err := instrumentation.New(instrumentation.Config{
	ServiceName:     "my-oauth-service",
	ServiceVersion:  "1.0.0",
	MetricsExporter: "prometheus",
	TracesExporter:  "otlp",
	OTLPEndpoint:    "localhost:4318", // OTLP HTTP endpoint
})
if err != nil {
	log.Fatal(err)
}

Zero Overhead (Default)

When exporters are not configured, the library uses no-op providers with zero overhead:

inst, err := instrumentation.New(instrumentation.Config{
	ServiceName:     "my-oauth-service",
	ServiceVersion:  "1.0.0",
	// MetricsExporter defaults to "none"
	// TracesExporter defaults to "none"
})
// No metrics or traces exported, zero performance impact

Available Metrics

HTTP Layer:

  • oauth.http.requests.total{method, endpoint, status} - Total HTTP requests
  • oauth.http.request.duration{endpoint} - Request duration in milliseconds

OAuth Flows:

  • oauth.authorization.started{client_id} - Authorization flows started
  • oauth.code.exchanged{client_id, pkce_method} - Authorization codes exchanged
  • oauth.token.refreshed{client_id, rotated} - Tokens refreshed
  • oauth.token.revoked{client_id} - Tokens revoked

Security:

  • oauth.rate_limit.exceeded{limiter_type} - Rate limit violations
  • oauth.pkce.validation_failed{method} - PKCE validation failures
  • oauth.code.reuse_detected - Authorization code reuse attempts
  • oauth.token.reuse_detected - Token reuse attempts

Storage:

  • storage.operation.total{operation, result} - Storage operations
  • storage.operation.duration{operation} - Operation duration in milliseconds
  • storage.size{type} - Current storage size (tokens, clients, flows)

Provider:

  • provider.api.calls.total{provider, operation, status} - Provider API calls
  • provider.api.duration{provider, operation} - API call duration in milliseconds
  • provider.api.errors.total{provider, operation, error_type} - Provider API errors

Distributed Tracing

Spans are created for all major operations:

  • HTTP requests (via otelhttp middleware)
  • OAuth flows (authorization, callback, token exchange, refresh, revocation)
  • Storage operations (save, get, delete)
  • Provider API calls (exchange, validate, refresh, revoke)

Example span structure:

http.request
├── oauth.http.authorization
│   └── oauth.server.start_authorization_flow
│       ├── storage.save_authorization_state
│       └── provider.google.authorization_url
└── oauth.http.callback
    └── oauth.server.handle_provider_callback
        ├── storage.get_authorization_state
        ├── provider.google.exchange_code
        └── storage.save_token

Performance

When instrumentation is not configured or disabled:

  • Zero overhead (uses no-op providers)
  • No allocations or latency impact

When enabled:

  • < 1% latency overhead
  • ~1-2 MB memory for metric registry
  • Lock-free atomic operations for metrics
  • Object pooling for span creation

Thread Safety

All instrumentation operations are thread-safe and can be called concurrently from multiple goroutines.

Metric Cardinality Considerations

Metric cardinality refers to the number of unique label combinations for a metric. High cardinality can cause memory pressure and slow queries in monitoring systems.

Label cardinality in this library:

  • client_id: One value per registered OAuth client (typically 1-1000s)
  • user_id: One value per authenticated user (can be high for consumer apps)
  • endpoint: Fixed set (5-10 endpoints)
  • operation: Fixed set (10-20 operations)
  • status: Fixed set (HTTP status codes ~10-20 values)
  • provider: Fixed set (number of identity providers, typically 1-5)

Cardinality recommendations:

LOW SCALE (<100 clients):

  • Use client_id labels freely for detailed per-client metrics
  • Track individual client operations and error rates
  • No special configuration needed

MEDIUM SCALE (100-10,000 clients):

  • Monitor total metric cardinality in your observability platform
  • Consider aggregating metrics by client type instead of client_id
  • Set recording rules in Prometheus to pre-aggregate high-cardinality metrics
  • Example: aggregate rate(oauth_token_refreshed_total[5m]) by client_type

HIGH SCALE (>10,000 clients):

  • REMOVE client_id labels from high-frequency metrics
  • Use sampling: only record metrics for a subset of clients
  • Implement custom metric aggregation in your application
  • Consider using exemplars (Prometheus 2.26+) to link metrics to traces
  • Use distributed tracing (spans) for per-client debugging instead of metrics

Estimating metric cardinality:

  • oauth.http.requests.total{method, endpoint, status}: ~3 methods * 10 endpoints * 20 statuses = 600 series
  • oauth.authorization.started{client_id}: N clients = N series (HIGH CARDINALITY)
  • oauth.token.refreshed{client_id, rotated}: N clients * 2 = 2N series (HIGH CARDINALITY)

For very high scale (millions of users/clients), consider:

  • Using aggregated metrics (total counts without client_id)
  • Sampling metrics (record 1% of operations)
  • Using logs or traces for per-client debugging
  • External systems like ClickHouse or BigQuery for high-cardinality analysis

Security Considerations

IMPORTANT: This package is designed to collect observability data, not sensitive credentials.

When instrumenting OAuth flows, you MUST:

  • NEVER log actual token values (access tokens, refresh tokens, authorization codes)
  • NEVER log client secrets or PKCE verifiers
  • ONLY log metadata (token types, expiry times, validation results, family IDs)

Data collected in traces and metrics may be:

  • Persisted for extended periods in observability backends
  • Accessible to operations teams and potentially wider audiences
  • Subject to compliance requirements (GDPR, PCI-DSS, SOC 2, etc.)
  • Replicated across monitoring infrastructure

Privacy considerations:

  • Client IP addresses may be considered PII in some jurisdictions
  • User IDs may be subject to privacy regulations
  • Configure appropriate retention policies and access controls
  • Document data collection in your privacy policy

See the README.md "Privacy & Compliance" section for detailed guidance.

Metric Cardinality Management

Cardinality refers to the number of unique time series created by metric labels. High cardinality can cause serious performance and cost issues in metrics backends.

## The Problem

Each unique combination of metric labels creates a new time series:

oauth.authorization.started{client_id="client1"} → time series 1
oauth.authorization.started{client_id="client2"} → time series 2
oauth.authorization.started{client_id="client3"} → time series 3

With 10,000 clients, you have 10,000 time series just for this one metric. With 20 metrics using client_id, that's 200,000 time series!

## Impact of High Cardinality

  • Memory Pressure: Each time series consumes RAM in Prometheus and other backends
  • Query Performance: Slower queries as cardinality increases
  • Storage Costs: More disk space and higher cloud storage costs
  • System Instability: Metrics backends can crash or become unresponsive

## Mitigation Strategies

### Strategy 1: Disable client_id in Metrics (Recommended for >1000 clients)

Set IncludeClientIDInMetrics: false in your configuration:

config := server.Config{
    Instrumentation: server.InstrumentationConfig{
        Enabled: true,
        IncludeClientIDInMetrics: false, // Low cardinality mode
        MetricsExporter: "prometheus",
    },
}

This provides aggregate metrics across all clients while keeping cardinality low. Use traces (not metrics) for per-client debugging.

### Strategy 2: Use Aggregations Instead of Labels

Instead of labeling by client_id, group clients into categories:

  • client_type: "public" vs "confidential"
  • tier: "free", "premium", "enterprise"
  • region: "us-east", "eu-west", "ap-south"

This reduces cardinality while preserving useful segmentation.

### Strategy 3: Sampling for High-Cardinality Labels

Only include client_id for specific clients you're debugging:

if clientID == "debug-client-123" {
    // Include client_id in this case
}

Or use a hash-based sampling (e.g., 1% of clients):

if hash(clientID) % 100 < 1 {
    // Include this client_id
}

### Strategy 4: Use Traces for Per-Client Details

Metrics are for aggregates, traces are for details:

  • Metrics: Track overall success rates, latencies, and trends
  • Traces: Debug specific client issues with full context

Traces support high cardinality attributes without backend pressure.

## Cardinality Guidelines by Scale

Clients     IncludeClientIDInMetrics    Strategy
--------    ------------------------    ----------------------------------
< 100       true                        Full per-client metrics
100-1,000   true                        Monitor backend performance
1,000-5,000 false                       Use traces for per-client debug
> 5,000     false                       Aggregate metrics + sampling

## Monitoring Your Cardinality

Prometheus provides cardinality metrics:

# Total time series
prometheus_tsdb_head_series

# Per-metric cardinality
count by (__name__) ({__name__=~".+"})

Set up alerts when cardinality exceeds safe thresholds for your infrastructure.

## Security Note

Disabling IncludeClientIDInMetrics also improves security:

  • Reduces exposure of client identifiers in metrics backends
  • Makes it harder to enumerate clients through metrics scraping
  • Limits information leakage if metrics are accidentally exposed

Index

Constants

View Source
const (
	// OAuth flow attributes - SAFE to use for metadata only
	AttrClientID         = "oauth.client_id"         // Client identifier (non-secret)
	AttrUserID           = "oauth.user_id"           // User identifier (non-secret)
	AttrScope            = "oauth.scope"             // Requested scopes
	AttrPKCEMethod       = "oauth.pkce.method"       // PKCE method used (S256, plain)
	AttrTokenFamilyID    = "oauth.token.family_id"   //nolint:gosec // Token family identifier for rotation tracking
	AttrTokenGeneration  = "oauth.token.generation"  //nolint:gosec // Token generation number
	AttrCodeReuse        = "oauth.code.reuse"        // Whether code reuse was detected (boolean)
	AttrTokenReuse       = "oauth.token.reuse"       //nolint:gosec // Whether token reuse was detected (boolean)
	AttrTokenRotated     = "oauth.token.rotated"     //nolint:gosec // Whether token was rotated (boolean)
	AttrGrantType        = "oauth.grant_type"        // OAuth grant type
	AttrResponseType     = "oauth.response_type"     // OAuth response type
	AttrClientType       = "oauth.client_type"       // Client type (public/confidential)
	AttrRedirectURI      = "oauth.redirect_uri"      // Redirect URI (may contain sensitive data)
	AttrState            = "oauth.state"             // OAuth state parameter
	AttrProviderState    = "oauth.provider_state"    // Provider-specific state
	AttrTokenType        = "oauth.token_type"        //nolint:gosec // Token type (Bearer, etc.) - NOT the actual token
	AttrExpiresIn        = "oauth.expires_in"        // Token expiry duration
	AttrError            = "oauth.error"             // Error code
	AttrErrorDescription = "oauth.error_description" // Error description

	// Storage attributes
	AttrStorageOperation = "storage.operation"
	AttrStorageResult    = "storage.result"
	AttrStorageType      = "storage.type"
	AttrStorageKey       = "storage.key"

	// Provider attributes
	AttrProviderName      = "provider.name"
	AttrProviderOperation = "provider.operation"
	AttrProviderStatus    = "provider.status"
	AttrProviderErrorType = "provider.error_type"

	// Security attributes
	AttrRateLimiterType     = "security.rate_limiter.type"
	AttrClientIP            = "security.client_ip"
	AttrAuditEventType      = "security.audit.event_type"
	AttrEncryptionOperation = "security.encryption.operation"

	// HTTP attributes (in addition to standard semantic conventions)
	AttrHTTPEndpoint     = "http.endpoint"
	AttrHTTPMethod       = "http.method"
	AttrHTTPStatusCode   = "http.status_code"
	AttrHTTPRequestSize  = "http.request.size"
	AttrHTTPResponseSize = "http.response.size"
)

Common span attribute keys

SECURITY WARNING: Never log actual sensitive values (access tokens, refresh tokens, authorization codes, client secrets, etc.) in traces or metrics. Only log metadata such as token types, expiry times, family IDs, and validation results.

These constants define attribute key names for observability, not for logging sensitive credential values. Logging actual credentials would create critical security vulnerabilities as traces are often:

  • Persisted for extended periods
  • Accessible to wider audiences than production systems
  • Replicated across monitoring infrastructure
  • Subject to compliance requirements (GDPR, PCI-DSS, etc.)
View Source
const (
	// DefaultServiceVersion is the default service version used when none is provided
	DefaultServiceVersion = "unknown"
)

Variables

This section is empty.

Functions

func AddHTTPAttributes

func AddHTTPAttributes(span trace.Span, method, endpoint string, statusCode int)

AddHTTPAttributes adds HTTP request attributes to a span (nil-safe)

func AddOAuthFlowAttributes

func AddOAuthFlowAttributes(span trace.Span, clientID, userID, scope string)

AddOAuthFlowAttributes adds common OAuth flow attributes to a span (nil-safe)

func AddPKCEAttributes

func AddPKCEAttributes(span trace.Span, method string)

AddPKCEAttributes adds PKCE-related attributes to a span (nil-safe)

func AddProviderAttributes

func AddProviderAttributes(span trace.Span, providerName, operation string)

AddProviderAttributes adds provider attributes to a span (nil-safe)

func AddSecurityAttributes

func AddSecurityAttributes(span trace.Span, clientIP string)

AddSecurityAttributes adds security-related attributes to a span (nil-safe)

PRIVACY NOTE: Client IP addresses may be considered Personally Identifiable Information (PII). Before calling this function, check if IP logging is enabled using instrumentation.ShouldLogClientIPs(). Example:

if inst.ShouldLogClientIPs() {
    AddSecurityAttributes(span, clientIP)
}

func AddStorageAttributes

func AddStorageAttributes(span trace.Span, operation, storageType string)

AddStorageAttributes adds storage operation attributes to a span (nil-safe)

func AddTokenFamilyAttributes

func AddTokenFamilyAttributes(span trace.Span, familyID string, generation int)

AddTokenFamilyAttributes adds token family tracking attributes to a span (nil-safe)

func RecordError

func RecordError(span trace.Span, err error)

RecordError records an error on a span with proper status codes (nil-safe)

func SanitizeRedirectURI

func SanitizeRedirectURI(uri string) string

SanitizeRedirectURI removes query parameters and fragments from a redirect URI This prevents accidentally logging sensitive data that might be passed via query params

SECURITY: While OAuth 2.1 best practices discourage sensitive data in redirect URIs, this function provides defense-in-depth by stripping query parameters and fragments before including the URI in traces or logs.

Example:

uri := "https://example.com/callback?secret=abc123#fragment"
sanitized := SanitizeRedirectURI(uri)
// Result: "https://example.com/callback"

func SetSpanAttributes

func SetSpanAttributes(span trace.Span, attrs ...attribute.KeyValue)

SetSpanAttributes sets attributes on a span (nil-safe) This is a convenience wrapper that safely handles nil spans

func SetSpanError

func SetSpanError(span trace.Span, message string)

SetSpanError sets an error status on a span (nil-safe) This is a convenience wrapper that safely handles nil spans

func SetSpanSuccess

func SetSpanSuccess(span trace.Span)

SetSpanSuccess marks a span as successful (nil-safe)

Types

type Config

type Config struct {
	// ServiceName is the name of the service (e.g., "mcp-oauth", "my-oauth-server")
	ServiceName string

	// ServiceVersion is the version of the service
	ServiceVersion string

	// Enabled controls whether instrumentation is active
	// When false (zero value), uses no-op providers (zero overhead)
	// When true, initializes exporters based on MetricsExporter and TracesExporter settings
	// You must explicitly set this to true to enable instrumentation
	Enabled bool

	// LogClientIPs controls whether client IP addresses are included in traces and metrics
	// Set to true to include client IP addresses in observability data
	// Set to false (zero value/default) to omit client IP for GDPR/privacy compliance
	//
	// Privacy Note: Client IP addresses may be considered Personally Identifiable
	// Information (PII) under GDPR and other privacy regulations. The default
	// behavior (false) omits IP addresses to be privacy-safe by default.
	// Only enable this if your privacy policy and jurisdiction allow it.
	LogClientIPs bool

	// IncludeClientIDInMetrics controls whether client_id is included as a label in metrics
	// Set to true to include client_id in metrics for detailed per-client visibility
	// Set to false (zero value/default) to reduce cardinality for high-scale deployments
	//
	// Cardinality Warning: Each unique client_id creates a new metric time series.
	// With 10,000+ clients, this can cause:
	// - Memory pressure on metrics backends (Prometheus, etc.)
	// - Slower query performance
	// - Higher storage costs
	//
	// Default (false) is recommended for production deployments with many clients.
	// Use traces with sampling for per-client debugging instead.
	IncludeClientIDInMetrics bool

	// MetricsExporter controls which metrics exporter to use
	// Options: "prometheus", "stdout", "none" (default: "none")
	// - "prometheus": Export metrics in Prometheus format (use prometheus.Handler())
	// - "stdout": Print metrics to stdout (useful for development/debugging)
	// - "none": Use no-op provider (zero overhead)
	MetricsExporter string

	// TracesExporter controls which traces exporter to use
	// Options: "otlp", "stdout", "none" (default: "none")
	// - "otlp": Export traces via OTLP HTTP (requires OTLPEndpoint)
	// - "stdout": Print traces to stdout (useful for development/debugging)
	// - "none": Use no-op provider (zero overhead)
	TracesExporter string

	// OTLPEndpoint is the endpoint for OTLP trace export
	// Required when TracesExporter="otlp"
	// Example: "localhost:4318" (default OTLP HTTP port)
	OTLPEndpoint string

	// OTLPInsecure controls whether to use insecure HTTP for OTLP export
	// When false (default), uses TLS for secure transport
	// Set to true only for local development or testing with unencrypted endpoints
	// Default: false (uses TLS)
	// WARNING: Never use insecure transport in production - traces may contain
	// user metadata and should be encrypted in transit
	OTLPInsecure bool

	// Resource allows custom resource attributes
	// If nil, default resource is created with service name and version
	Resource *resource.Resource
}

Config holds instrumentation configuration

type ForwardedIDTokenResult added in v0.2.102

type ForwardedIDTokenResult string

ForwardedIDTokenResult is the bounded result enum for the oauth.forwarded_id_token.accepted_total counter. Declared as a typed string so the compiler enforces the closed set — callers cannot pass raw error strings (label cardinality matters).

const (
	ForwardedIDTokenResultOK          ForwardedIDTokenResult = "ok"
	ForwardedIDTokenResultAudMismatch ForwardedIDTokenResult = "aud_mismatch"
	ForwardedIDTokenResultIssMismatch ForwardedIDTokenResult = "iss_mismatch"
	ForwardedIDTokenResultSigInvalid  ForwardedIDTokenResult = "sig_invalid"
	ForwardedIDTokenResultExpired     ForwardedIDTokenResult = "expired"
	ForwardedIDTokenResultNotYetValid ForwardedIDTokenResult = "not_yet_valid"
	ForwardedIDTokenResultNoJWKS      ForwardedIDTokenResult = "no_jwks"
	ForwardedIDTokenResultParseError  ForwardedIDTokenResult = "parse_error"
)

type Instrumentation

type Instrumentation struct {
	// contains filtered or unexported fields
}

Instrumentation provides OpenTelemetry instrumentation components

func New

func New(config Config) (*Instrumentation, error)

New creates a new instrumentation instance

func (*Instrumentation) Meter

func (i *Instrumentation) Meter(scope string) metric.Meter

Meter returns a named meter for the given scope Scopes are typically layer names like "http", "server", "storage", "provider", "security" The full name will be "github.com/giantswarm/mcp-oauth/{scope}"

func (*Instrumentation) MeterProvider

func (i *Instrumentation) MeterProvider() metric.MeterProvider

MeterProvider returns the underlying meter provider

func (*Instrumentation) Metrics

func (i *Instrumentation) Metrics() *Metrics

Metrics returns the metrics holder for recording metric values

func (*Instrumentation) PrometheusExporter

func (i *Instrumentation) PrometheusExporter() *prometheus.Exporter

PrometheusExporter returns the Prometheus exporter if configured Returns nil if MetricsExporter is not "prometheus"

Usage with prometheus/client_golang:

import "github.com/prometheus/client_golang/prometheus/promhttp"

if exporter := inst.PrometheusExporter(); exporter != nil {
    http.Handle("/metrics", promhttp.Handler())
}

func (*Instrumentation) RegisterStorageSizeCallbacks

func (i *Instrumentation) RegisterStorageSizeCallbacks(
	tokensCount, clientsCount, flowsCount, familiesCount, refreshTokensCount StorageSizeCallback,
) error

RegisterStorageSizeCallbacks registers callbacks for storage size metrics Storage implementations should call this after instrumentation is set

Example:

func (s *Store) SetInstrumentation(inst *instrumentation.Instrumentation) {
    s.instrumentation = inst
    inst.RegisterStorageSizeCallbacks(
        func() int64 { return int64(len(s.tokens)) },
        func() int64 { return int64(len(s.clients)) },
        func() int64 { return int64(len(s.authStates)) },
        func() int64 { return int64(len(s.refreshTokenFamilies)) },
        func() int64 { return int64(len(s.refreshTokens)) },
    )
}

func (*Instrumentation) ShouldIncludeClientIDInMetrics

func (i *Instrumentation) ShouldIncludeClientIDInMetrics() bool

ShouldIncludeClientIDInMetrics returns whether client_id should be included in metric labels This respects the IncludeClientIDInMetrics configuration for cardinality management

func (*Instrumentation) ShouldLogClientIPs

func (i *Instrumentation) ShouldLogClientIPs() bool

ShouldLogClientIPs returns whether client IP addresses should be logged This respects the LogClientIPs configuration for privacy compliance

func (*Instrumentation) Shutdown

func (i *Instrumentation) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down all instrumentation providers This should be called when the application is terminating

func (*Instrumentation) Tracer

func (i *Instrumentation) Tracer(scope string) trace.Tracer

Tracer returns a named tracer for the given scope Scopes are typically layer names like "http", "server", "storage", "provider", "security" The full name will be "github.com/giantswarm/mcp-oauth/{scope}"

func (*Instrumentation) TracerProvider

func (i *Instrumentation) TracerProvider() trace.TracerProvider

TracerProvider returns the underlying tracer provider

type Metrics

type Metrics struct {
	// HTTP Layer Metrics
	HTTPRequestsTotal   metric.Int64Counter
	HTTPRequestDuration metric.Float64Histogram

	// OAuth Flow Metrics
	AuthorizationStarted metric.Int64Counter
	CallbackProcessed    metric.Int64Counter
	CodeExchanged        metric.Int64Counter
	TokenRefreshed       metric.Int64Counter
	TokenRevoked         metric.Int64Counter
	ClientRegistered     metric.Int64Counter

	// Security Metrics
	RateLimitExceeded           metric.Int64Counter
	PKCEValidationFailed        metric.Int64Counter
	CodeReuseDetected           metric.Int64Counter
	TokenReuseDetected          metric.Int64Counter
	RedirectURISecurityRejected metric.Int64Counter // Redirect URI validation failures by category
	LegacyRefreshTokenRejected  metric.Int64Counter // Legacy refresh tokens rejected (missing client binding)
	ForwardedIDTokenAccepted    metric.Int64Counter // Forwarded ID token acceptance attempts (labels: issuer, audience, result)

	// Storage Metrics
	StorageOperationTotal    metric.Int64Counter
	StorageOperationDuration metric.Float64Histogram
	// Storage size gauges (observable) - updated via callbacks from storage implementations
	StorageTokensCount        metric.Int64ObservableGauge
	StorageClientsCount       metric.Int64ObservableGauge
	StorageFlowsCount         metric.Int64ObservableGauge
	StorageFamiliesCount      metric.Int64ObservableGauge
	StorageRefreshTokensCount metric.Int64ObservableGauge

	// Provider Metrics
	ProviderAPICallsTotal metric.Int64Counter
	ProviderAPIDuration   metric.Float64Histogram
	ProviderAPIErrors     metric.Int64Counter

	// Audit Metrics
	AuditEventsTotal metric.Int64Counter

	// Encryption Metrics
	EncryptionOperationsTotal metric.Int64Counter
	EncryptionDuration        metric.Float64Histogram

	// CIMD (Client ID Metadata Document) Metrics
	CIMDFetchTotal    metric.Int64Counter     // Total fetch attempts (labels: result=success/error/blocked)
	CIMDFetchDuration metric.Float64Histogram // Fetch duration in milliseconds
	CIMDCacheTotal    metric.Int64Counter     // Cache operations (labels: operation=hit/miss/negative_hit)
	// contains filtered or unexported fields
}

Metrics holds all metric instruments for the OAuth library

func (*Metrics) RecordAuditEvent

func (m *Metrics) RecordAuditEvent(ctx context.Context, eventType string)

RecordAuditEvent records an audit event

func (*Metrics) RecordAuthorizationStarted

func (m *Metrics) RecordAuthorizationStarted(ctx context.Context, clientID string)

RecordAuthorizationStarted records an authorization flow start

func (*Metrics) RecordCIMDCache added in v0.2.22

func (m *Metrics) RecordCIMDCache(ctx context.Context, operation string)

RecordCIMDCache records a CIMD cache operation. This metric helps monitor cache hit/miss rates for CIMD metadata.

Parameters:

  • operation: The type of cache operation ("hit", "miss", or "negative_hit")

func (*Metrics) RecordCIMDFetch added in v0.2.22

func (m *Metrics) RecordCIMDFetch(ctx context.Context, result string, durationMs float64)

RecordCIMDFetch records a Client ID Metadata Document fetch attempt. This metric helps track CIMD fetch latency and success/failure rates.

Parameters:

  • result: The outcome of the fetch ("success", "error", or "blocked")
  • durationMs: The duration of the fetch operation in milliseconds

func (*Metrics) RecordCallbackProcessed

func (m *Metrics) RecordCallbackProcessed(ctx context.Context, clientID string, success bool)

RecordCallbackProcessed records a provider callback processing

func (*Metrics) RecordClientRegistration

func (m *Metrics) RecordClientRegistration(ctx context.Context, clientType string)

RecordClientRegistration records a client registration

func (*Metrics) RecordCodeExchange

func (m *Metrics) RecordCodeExchange(ctx context.Context, clientID, pkceMethod string)

RecordCodeExchange records an authorization code exchange

func (*Metrics) RecordCodeReuseDetected

func (m *Metrics) RecordCodeReuseDetected(ctx context.Context)

RecordCodeReuseDetected records an authorization code reuse attempt

func (*Metrics) RecordEncryptionOperation

func (m *Metrics) RecordEncryptionOperation(ctx context.Context, operation string, durationMs float64)

RecordEncryptionOperation records an encryption/decryption operation

func (*Metrics) RecordForwardedIDTokenAccepted added in v0.2.102

func (m *Metrics) RecordForwardedIDTokenAccepted(ctx context.Context, provider, issuer, audience string, result ForwardedIDTokenResult)

RecordForwardedIDTokenAccepted records a forwarded ID token acceptance attempt. `provider` is the provider name (e.g. "dex", "google") so the metric is self-describing without consumers having to cross-reference server config. For unmatched-audience / parse-error / no-jwks cases, pass the empty string as `audience` rather than a token-derived value to keep cardinality bounded. Threads ctx through so OTel trace/baggage correlation survives on the metric.

func (*Metrics) RecordHTTPRequest

func (m *Metrics) RecordHTTPRequest(ctx context.Context, method, endpoint string, statusCode int, durationMs float64)

RecordHTTPRequest records an HTTP request metric

func (*Metrics) RecordLegacyRefreshTokenRejected added in v0.2.42

func (m *Metrics) RecordLegacyRefreshTokenRejected(ctx context.Context)

RecordLegacyRefreshTokenRejected records rejection of a legacy refresh token without client binding. This metric tracks rejected tokens for observability and security monitoring.

func (*Metrics) RecordPKCEValidationFailed

func (m *Metrics) RecordPKCEValidationFailed(ctx context.Context, method string)

RecordPKCEValidationFailed records a PKCE validation failure

func (*Metrics) RecordProviderAPICall

func (m *Metrics) RecordProviderAPICall(ctx context.Context, provider, operation string, statusCode int, durationMs float64, err error)

RecordProviderAPICall records a provider API call

func (*Metrics) RecordRateLimitExceeded

func (m *Metrics) RecordRateLimitExceeded(ctx context.Context, limiterType string)

RecordRateLimitExceeded records a rate limit violation

func (*Metrics) RecordRedirectURISecurityRejected added in v0.2.18

func (m *Metrics) RecordRedirectURISecurityRejected(ctx context.Context, category, stage string)

RecordRedirectURISecurityRejected records a redirect URI security validation failure. This metric helps monitor SSRF and XSS attack attempts.

Parameters:

  • category: The error category (e.g., "blocked_scheme", "private_ip", "link_local", "dns_resolves_to_private_ip", "loopback_not_allowed", "http_not_allowed")
  • stage: When the rejection occurred ("registration" or "authorization")

func (*Metrics) RecordStorageOperation

func (m *Metrics) RecordStorageOperation(ctx context.Context, operation, result string, durationMs float64)

RecordStorageOperation records a storage operation

func (*Metrics) RecordTokenRefresh

func (m *Metrics) RecordTokenRefresh(ctx context.Context, clientID string, rotated bool)

RecordTokenRefresh records a token refresh operation

func (*Metrics) RecordTokenReuseDetected

func (m *Metrics) RecordTokenReuseDetected(ctx context.Context)

RecordTokenReuseDetected records a token reuse attempt

func (*Metrics) RecordTokenRevocation

func (m *Metrics) RecordTokenRevocation(ctx context.Context, clientID string)

RecordTokenRevocation records a token revocation

type StorageSizeCallback

type StorageSizeCallback func() int64

StorageSizeCallback is a function that returns the current size of a storage component

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL