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
- func AddHTTPAttributes(span trace.Span, method, endpoint string, statusCode int)
- func AddOAuthFlowAttributes(span trace.Span, clientID, userID, scope string)
- func AddPKCEAttributes(span trace.Span, method string)
- func AddProviderAttributes(span trace.Span, providerName, operation string)
- func AddSecurityAttributes(span trace.Span, clientIP string)
- func AddStorageAttributes(span trace.Span, operation, storageType string)
- func AddTokenFamilyAttributes(span trace.Span, familyID string, generation int)
- func RecordError(span trace.Span, err error)
- func SanitizeRedirectURI(uri string) string
- func SetSpanAttributes(span trace.Span, attrs ...attribute.KeyValue)
- func SetSpanError(span trace.Span, message string)
- func SetSpanSuccess(span trace.Span)
- type Config
- type ForwardedIDTokenResult
- type Instrumentation
- func (i *Instrumentation) Meter(scope string) metric.Meter
- func (i *Instrumentation) MeterProvider() metric.MeterProvider
- func (i *Instrumentation) Metrics() *Metrics
- func (i *Instrumentation) PrometheusExporter() *prometheus.Exporter
- func (i *Instrumentation) RegisterStorageSizeCallbacks(...) error
- func (i *Instrumentation) ShouldIncludeClientIDInMetrics() bool
- func (i *Instrumentation) ShouldLogClientIPs() bool
- func (i *Instrumentation) Shutdown(ctx context.Context) error
- func (i *Instrumentation) Tracer(scope string) trace.Tracer
- func (i *Instrumentation) TracerProvider() trace.TracerProvider
- type Metrics
- func (m *Metrics) RecordAuditEvent(ctx context.Context, eventType string)
- func (m *Metrics) RecordAuthorizationStarted(ctx context.Context, clientID string)
- func (m *Metrics) RecordCIMDCache(ctx context.Context, operation string)
- func (m *Metrics) RecordCIMDFetch(ctx context.Context, result string, durationMs float64)
- func (m *Metrics) RecordCallbackProcessed(ctx context.Context, clientID string, success bool)
- func (m *Metrics) RecordClientRegistration(ctx context.Context, clientType string)
- func (m *Metrics) RecordCodeExchange(ctx context.Context, clientID, pkceMethod string)
- func (m *Metrics) RecordCodeReuseDetected(ctx context.Context)
- func (m *Metrics) RecordEncryptionOperation(ctx context.Context, operation string, durationMs float64)
- func (m *Metrics) RecordForwardedIDTokenAccepted(ctx context.Context, provider, issuer, audience string, ...)
- func (m *Metrics) RecordHTTPRequest(ctx context.Context, method, endpoint string, statusCode int, ...)
- func (m *Metrics) RecordLegacyRefreshTokenRejected(ctx context.Context)
- func (m *Metrics) RecordPKCEValidationFailed(ctx context.Context, method string)
- func (m *Metrics) RecordProviderAPICall(ctx context.Context, provider, operation string, statusCode int, ...)
- func (m *Metrics) RecordRateLimitExceeded(ctx context.Context, limiterType string)
- func (m *Metrics) RecordRedirectURISecurityRejected(ctx context.Context, category, stage string)
- func (m *Metrics) RecordStorageOperation(ctx context.Context, operation, result string, durationMs float64)
- func (m *Metrics) RecordTokenRefresh(ctx context.Context, clientID string, rotated bool)
- func (m *Metrics) RecordTokenReuseDetected(ctx context.Context)
- func (m *Metrics) RecordTokenRevocation(ctx context.Context, clientID string)
- type StorageSizeCallback
Constants ¶
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.)
const (
// DefaultServiceVersion is the default service version used when none is provided
DefaultServiceVersion = "unknown"
)
Variables ¶
This section is empty.
Functions ¶
func AddHTTPAttributes ¶
AddHTTPAttributes adds HTTP request attributes to a span (nil-safe)
func AddOAuthFlowAttributes ¶
AddOAuthFlowAttributes adds common OAuth flow attributes to a span (nil-safe)
func AddPKCEAttributes ¶
AddPKCEAttributes adds PKCE-related attributes to a span (nil-safe)
func AddProviderAttributes ¶
AddProviderAttributes adds provider attributes to a span (nil-safe)
func AddSecurityAttributes ¶
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 ¶
AddStorageAttributes adds storage operation attributes to a span (nil-safe)
func AddTokenFamilyAttributes ¶
AddTokenFamilyAttributes adds token family tracking attributes to a span (nil-safe)
func RecordError ¶
RecordError records an error on a span with proper status codes (nil-safe)
func SanitizeRedirectURI ¶
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 ¶
SetSpanAttributes sets attributes on a span (nil-safe) This is a convenience wrapper that safely handles nil spans
func SetSpanError ¶
SetSpanError sets an error status on a span (nil-safe) This is a convenience wrapper that safely handles nil spans
func SetSpanSuccess ¶
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 ¶
RecordAuditEvent records an audit event
func (*Metrics) RecordAuthorizationStarted ¶
RecordAuthorizationStarted records an authorization flow start
func (*Metrics) RecordCIMDCache ¶ added in v0.2.22
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
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 ¶
RecordCallbackProcessed records a provider callback processing
func (*Metrics) RecordClientRegistration ¶
RecordClientRegistration records a client registration
func (*Metrics) RecordCodeExchange ¶
RecordCodeExchange records an authorization code exchange
func (*Metrics) RecordCodeReuseDetected ¶
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
RecordLegacyRefreshTokenRejected records rejection of a legacy refresh token without client binding. This metric tracks rejected tokens for observability and security monitoring.
func (*Metrics) RecordPKCEValidationFailed ¶
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 ¶
RecordRateLimitExceeded records a rate limit violation
func (*Metrics) RecordRedirectURISecurityRejected ¶ added in v0.2.18
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 ¶
RecordTokenRefresh records a token refresh operation
func (*Metrics) RecordTokenReuseDetected ¶
RecordTokenReuseDetected records a token reuse attempt
type StorageSizeCallback ¶
type StorageSizeCallback func() int64
StorageSizeCallback is a function that returns the current size of a storage component