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
53 lines
1.6 KiB
Go
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)
|
|
}
|