-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Description
Component(s)
extension/bearertokenauth
What happened?
Description
The bearertokenauthextension fails to authenticate HTTP requests when configured with a custom header (e.g., X-API-Key) instead of the default Authorization header. This affects HTTP-based receivers like faroreceiver, prometheusreceiver, otlpreceiver (HTTP), and others that use the bearer token authenticator.
The root cause is that Go's HTTP server automatically canonicalizes all header names using http.CanonicalHeaderKey() (e.g., X-API-Key → X-Api-Key), but the extension's authentication logic doesn't account for this canonicalization when looking up custom headers. The current implementation attempts to look for the custom header in the header map with two specific keys; one in lowercase form of the provided custom header and the second using the exact string as specified in the config.
Steps to Reproduce
Here is a docker-compose example illustrating this behavior. Both the docker-compose.yml and otel-config.yaml config files have been attached.
- Download the following files:
- Spin up the docker-compose environment with the collector and test client by running
docker-compose up. An OTLP HTTP receiver is configured with the bearertokenauth extension using the custom headerX-API-KEYand token valuesecret-token-12345. The test client runs cURL commands to test the following cases:
- Header specified in lowercase: x-api-key
- Header specified in uppercase: X-API-KEY
- Header specified in mixed case: X-API-Key
- Header specified in the canonical form: X-Api-Key
- Header specified in the canonical form but with an incorrect token
- Missing custom header
Expected Result
The request should be authenticated successfully and processed by the receiver for test cases 1-4.
The request should be rejected for test cases 5 and 6.
Actual Result
The collector returns 401 Unauthorized for all test cases even though the correct token is provided for cases 1-4. The authentication fails because:
- Client sends the header:
X-API-Key: secret-token-12345(example mixed case) - Go's HTTP server canonicalizes it to:
X-Api-Key: secret-token-12345 - Extension checks for:
x-api-key(lowercase) andX-API-Key(exact case) - Extension misses:
X-Api-Key(canonical form that's actually in the header map) - Authentication fails → 401 error
Note: This only affects custom headers. The default Authorization header works correctly because it's already being looked up using the canonical form.
Workaround
The current workaround is to specify the custom header string in the config file specifically in the canonical form such that when the exact case check occurs on L228 it is compared to the canonical form of the header stored in the header map. Here is the same docker-compose example illustrating the work around:
We are currently using this work around and its fine for the time being - however ideally from a user perspective it should be acceptable to specify custom header string in any format given headers are case insensitive.
Collector version
v0.144.0 (latest docker image)
Environment information
OpenTelemetry Collector configuration
extensions:
bearertokenauth:
# Custom header instead of default "Authorization"
header: "X-API-KEY"
token: "secret-token-12345"
scheme: ""
health_check:
endpoint: 0.0.0.0:13133
receivers:
# Using OTLP HTTP receiver to demonstrate the bug
otlp:
protocols:
http:
endpoint: 0.0.0.0:12347
auth:
authenticator: bearertokenauth
exporters:
debug:
verbosity: detailed
service:
extensions: [bearertokenauth, health_check]
pipelines:
traces:
receivers: [otlp]
exporters: [debug]
metrics:
receivers: [otlp]
exporters: [debug]
logs:
receivers: [otlp]
exporters: [debug]
telemetry:
logs:
level: infoLog output
Additional context
No response
Tip
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.