OpenTelemetry Collector extensions can authenticate and authorize requests to your Collector, but they don’t block unauthorized requests; they simply determine if a request is authorized, and then pass it along to other components.

Let’s look at how the Collector handles authentication and authorization using extensions.

Imagine you have a service that needs to send metrics to your OpenTelemetry Collector. This service needs to prove its identity to the Collector, and the Collector needs to decide if it’s allowed to send those metrics. This is where authentication and authorization come in, and extensions are the primary mechanism for this.

Here’s a typical setup:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:

exporters:
  logging:
    loglevel: debug

extensions:
  basicauth:
    client_auth:
      username: "myuser"
      password: "mypassword"
  oauth2client:
    client_id: "my-client-id"
    client_secret: "my-client-secret"
    scopes:
      - "openid"
      - "profile"

service:
  pipelines:
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [logging]
  extensions: [basicauth, oauth2client]

In this configuration, we have two extensions: basicauth and oauth2client. The basicauth extension expects incoming requests to have a Authorization: Basic <base64-encoded username:password> header. The oauth2client extension, on the other hand, is designed for the Collector to act as a client, obtaining tokens to authenticate with an upstream service, which isn’t directly used for incoming request authorization in this setup.

When a request arrives at the otlp receiver, the Collector doesn’t immediately process it. Instead, it consults its configured extensions. If basicauth is enabled, it checks for the presence and validity of the Authorization header. If the credentials match myuser:mypassword, the extension might add some context to the request, indicating successful authentication. However, it doesn’t stop the request from proceeding.

The real power comes when you combine extensions with other components, like authorization policies. While the Collector doesn’t have a built-in, opinionated authorization policy engine that inspects content or attributes of the incoming data based on authenticated identity, you can achieve this by:

  1. Writing a custom extension: This extension can inspect the authenticated identity (e.g., from basicauth or a custom token validation) and then make a decision about whether to allow the data to proceed. It could reject the request by returning an error, or it could add attributes to the data indicating authorization status.
  2. Using a proxy: A dedicated proxy (like Envoy or Nginx) in front of the Collector can handle complex authorization logic. The proxy authenticates the client, and then forwards the request to the Collector, potentially adding headers that the Collector’s custom extension can then interpret.

Let’s say you want to use basicauth to authorize requests. The incoming request would look like this:

POST /v1/metrics HTTP/1.1
Host: your-collector-host:4318
Authorization: Basic bXl1c2VyOm15cGFzc3dvcmQ=
Content-Type: application/json
...

The base64 encoded bXl1c2VyOm15cGFzc3dvcmQ= decodes to myuser:mypassword. The basicauth extension checks this. If it matches, it essentially says, "This user is authenticated."

The most surprising truth about OpenTelemetry Collector extensions and authentication is that they are primarily identity providers and context enrichers, not gatekeepers. An extension like basicauth verifies who is sending the data, but it doesn’t inherently restrict what data they can send or how much. The decision to allow or deny based on identity and data attributes typically needs to be handled by a more sophisticated authorization layer, either a custom extension that implements policy logic or an external system.

Consider a scenario where you have multiple services sending data. You might want to restrict service-a to only sending metrics related to its own domain, while service-b can send a broader range. The basicauth extension alone can’t do this. You would need a custom authorization extension that, after verifying the username from basicauth, inspects attributes on the incoming telemetry (e.g., service.name, resource.attributes) and decides whether to allow or drop the data.

This is where the mental model needs refinement: extensions are components that run alongside the Collector’s main data processing pipeline. They can intercept requests, perform actions (like authentication), and potentially modify the request context or the telemetry data itself before it hits the processors and exporters. They don’t typically terminate the request pipeline themselves unless they are specifically designed to do so and return an error.

The oauth2client extension, while configured for authentication, is designed for the Collector to obtain OAuth2 tokens to authenticate itself to an upstream service (like a SaaS observability platform). It’s not for authenticating clients sending data to the Collector. This is a common point of confusion.

If you’re implementing fine-grained access control, you’ll likely need to build a custom extension that integrates with your identity provider and implements your authorization policies. This custom extension would then be listed in the service.extensions section, just like basicauth. It would receive the request, perform its authorization checks, and then decide whether to pass the data along or reject it.

The next conceptual hurdle after understanding how extensions authenticate is how to enforce authorization policies based on that authentication.

Want structured learning?

Take the full Opentelemetry course →