Files
common/internal/tracerconfig/auth.go
Ask Bjørn Hansen 1df4b0d4b4 feat(tracing): add bearer token authentication for OTLP exporters
Add BearerTokenFunc to support dynamic bearer token authentication
for OTLP exporters. Tokens are injected per-request via gRPC
PerRPCCredentials and HTTP custom RoundTripper.

- Add BearerTokenFunc type and Config field in tracerconfig
- Implement bearerCredentials (gRPC) and bearerRoundTripper (HTTP)
- Wire bearer auth into all exporter creation functions
- Add getHTTPClient helper for DRY HTTP client configuration
- Upgrade OpenTelemetry SDK to v1.39.0 for WithHTTPClient support
2026-01-01 03:39:01 -08:00

53 lines
1.6 KiB
Go

package tracerconfig
import (
"context"
"net/http"
)
// bearerCredentials implements gRPC PerRPCCredentials for bearer token authentication.
// It is safe for concurrent use as required by the gRPC PerRPCCredentials interface.
type bearerCredentials struct {
tokenFunc BearerTokenFunc
}
// GetRequestMetadata returns authorization metadata for each RPC call.
// It calls the token function to retrieve the current token.
func (c *bearerCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
token, err := c.tokenFunc(ctx)
if err != nil {
return nil, err
}
if token == "" {
return nil, nil // Omit header for empty token
}
return map[string]string{"authorization": "Bearer " + token}, nil
}
// RequireTransportSecurity returns true because bearer tokens require TLS.
func (c *bearerCredentials) RequireTransportSecurity() bool {
return true
}
// bearerRoundTripper wraps an http.RoundTripper to add bearer token authentication.
// It is safe for concurrent use as required by the http.RoundTripper interface.
type bearerRoundTripper struct {
base http.RoundTripper
tokenFunc BearerTokenFunc
}
// RoundTrip adds the Authorization header with the bearer token.
func (rt *bearerRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
token, err := rt.tokenFunc(req.Context())
if err != nil {
return nil, err
}
if token == "" {
return rt.base.RoundTrip(req)
}
// Clone only when adding a header to preserve the original request
req = req.Clone(req.Context())
req.Header.Set("Authorization", "Bearer "+token)
return rt.base.RoundTrip(req)
}