This repository contains small test projects that demonstrate a token service used to authenticate clients (for example: an OpenTelemetry Collector) against an OpenID Connect / token provider running on Windows Server.
This README documents how to deploy the token service to IIS on Windows Server and how to configure the OpenTelemetry Collector to use tokens issued by this service for authentication. It assumes the projects in the dev/ folder have been built and the resulting binaries are available.
- Windows Server 2019 or newer with IIS installed
- .NET SDK matching the projects in this repository (check
global.json) - Administrative access to the server to configure IIS and firewall rules
- On a developer machine, publish the ASP.NET app (example path:
src/AlbusKavaliro.WinTokenBridgeordev/AppHost) for Release:
dotnet publish -c Release -o .\publish- Copy the
publishfolder to the Windows Server where IIS will host the service (for exampleC:\inetpub\wwwroot\TokenService). Ensure the folder contains the executable andweb.config(or create one as described below).
-
Open
Server Manager→Add roles and featuresand ensureWeb Server (IIS)is installed with theApplication Developmentfeatures for.NETandASP.NET. -
Open
Internet Information Services (IIS) Manager. -
Create a new Application Pool:
- Name:
TokenServicePool - .NET CLR Version:
No Managed Code(for out-of-process hosting with ANCM) - Managed pipeline mode:
Integrated
- Name:
-
Add a new Website or Application:
- Site name:
TokenService - Physical path:
C:\inetpub\wwwroot\TokenService(the folder you copied) - Application Pool:
TokenServicePool - Binding: set the hostname and port (e.g.,
httpson443with your certificate). Use a proper hostname instead of 0.0.0.0.
- Site name:
-
Configure HTTPS:
- Add an SSL certificate to the server and bind it to the site's HTTPS binding.
-
Optional: If the app uses Windows environment variables for URLs, set them in the system-level Environment Variables or in
web.configas appSettings.
Ensure the server firewall allows inbound traffic on the ports you bind (e.g. 443 for HTTPS). If the collector will be hosted elsewhere, ensure that host can reach the token service URL.
Below is an example snippet adapted from dev/AppHost/collector-with-token-auth.yaml. Note the following changes compared to older examples:
- The token service is configured with a collection of allowed audiences (
Oidc:Audiences). - When requesting a token clients MUST provide a
client_idparameter; the issued token will be valid for that single audience (theaudclaim will contain exactly one value). - The token service exposes additional configuration options under the
Oidcsection. See theOidcOptionsclass for details. Important options include:Issuer: Canonical issuer override (important when different callers reach the service via different hosts). Set this when the externally-visible issuer differs from the server's local address.SigningCertThumbprint: Thumbprint of a certificate in the local machine store to prefer when signing tokens.SigningCertSubjectPattern: Regular expression used to match certificate subjects in the local machine store when selecting a signing certificate.SigningPfxPath: Optional path to a PFX file that contains the signing certificate. When present the service will attempt to load the PFX (usingEphemeralKeySet) and use it if valid.SigningPfxPassword: Password for the PFX referenced bySigningPfxPath(only used if a PFX path is supplied).Audiences: One or more audiences to set on issued tokens (maps to the JWTaudclaim). Configure as a collection. A token issued in a single request will only be valid for a single audience (clients must request aclient_id).
extensions:
oidc:
providers:
- issuer_url: ${env:TOKENSERVER_HTTP}
audience: my-app
username_claim: sub
groups_claim: role
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
auth:
authenticator: oidc
http:
endpoint: 0.0.0.0:4318
auth:
authenticator: oidc
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [someotlp]
extensions: [oidc]The token service supports Windows Integrated Authentication for environments where clients can negotiate Kerberos/NTLM with the server. Below are simple examples showing how a client can request a token from the /token endpoint. Replace https://tokens.example.com/token with your token service URL and supply the client_id (audience) you need.
- .NET
HttpClient(Negotiate/DefaultCredentials):
using System.Net.Http;
using System.Collections.Generic;
var handler = new HttpClientHandler { UseDefaultCredentials = true };
using var http = new HttpClient(handler) { BaseAddress = new Uri("https://tokens.example.com") };
var form = new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["client_id"] = "my-app"
};
var resp = await http.PostAsync("/token", new FormUrlEncodedContent(form));
resp.EnsureSuccessStatusCode();
var json = await resp.Content.ReadAsStringAsync();
// parse JSON and extract access_token- PowerShell (Invoke-RestMethod with Negotiate):
$tokenServer = 'https://tokens.example.com'
$response = Invoke-RestMethod -Uri "$tokenServer/token" -Method Post -Body @{ grant_type = 'client_credentials'; client_id = 'my-app' } -Authentication Negotiate -UseDefaultCredentials
$response.access_token- curl (GSSAPI / Negotiate) — requires curl built with GSSAPI support and a valid Kerberos ticket:
curl --negotiate -u : -X POST \
-d "grant_type=client_credentials&client_id=my-app" \
https://tokens.example.com/tokenNotes:
- Use HTTPS and trust the server certificate in production.
- When using Kerberos, ensure SPNs and hostnames match the server's certificate and the configured
Issuerif you override it. - The examples post a
client_idwhich the service maps into the issued token'saudclaim. Adjustgrant_typeand parameters if your setup requires different flows.
OpenTelemetry .NET supports configuring the OTLP exporters to use a custom HttpClient (or HttpClientFactory) so you can attach authentication headers. See the OpenTelemetry .NET project for details: https://github.com/open-telemetry/opentelemetry-dotnet
In this repository the dev/DataProducer project demonstrates how to integrate token retrieval into exporter HTTP requests. The project registers a TokenRetrievalHandler which adds an Authorization: Bearer <token> header to outgoing OTLP exporter requests when needed.
Two recommended approaches when using OpenTelemetry.Exporter.OpenTelemetryProtocol are:
- Configure the exporter to use a named
HttpClient(recommended when you useIHttpClientFactory) and register aDelegatingHandlerto attach tokens. TheOtlpTraceExporterand friends will use named clients if available; see the exporter docs for the exact client names. - Use
OtlpExporterOptions.HttpClientFactory(when usingHttpProtobufprotocol) to return anHttpClientinstance configured with default headers or handlers.
Example (based on dev/DataProducer/Program.cs) — registers named OTLP clients and a TokenRetrievalHandler:
// In Program.cs
builder.Services.AddTransient<TokenRetrievalHandler>();
// Configure the HttpClient used by OTLP exporters to use Windows Integrated Auth when contacting the token server
builder.Services.AddHttpClient("OtlpTraceExporter")
.AddHttpMessageHandler<TokenRetrievalHandler>();
// For metrics/logs exporters use the same pattern with "OtlpMetricExporter" / "OtlpLogExporter"
// The TokenRetrievalHandler is responsible for requesting a token (using Windows Integrated Auth)
// and adding the Authorization header to the outgoing OTLP request when the exporter receives HTTP 401 responses.If you prefer to configure the exporter directly, use HttpClientFactory on OtlpExporterOptions:
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing.AddOtlpExporter(o =>
{
o.Protocol = OtlpExportProtocol.HttpProtobuf;
o.HttpClientFactory = () =>
{
var handler = new HttpClientHandler { UseDefaultCredentials = true };
var client = new HttpClient(new DelegatingHandlerWithToken(handler));
client.BaseAddress = new Uri("https://collector.example.com/v1/traces");
return client;
};
}));
// DelegatingHandlerWithToken would be a small delegating handler that obtains a token (for example via ITokenService)
// and attaches the Authorization header prior to sending the request.References:
- OpenTelemetry .NET repository: https://github.com/open-telemetry/opentelemetry-dotnet
- OTLP exporter docs (HttpClientFactory, Headers, named clients): https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md
- Use HTTPS for all production endpoints and ensure certificates are trusted by clients.
- The
issuer_urlin the collector must exactly match the token issuer'sissclaim and the service's discovery endpoint if using OIDC discovery. - If your token service requires client credentials or basic auth for certain flows, configure those credentials as environment variables and keep them out of source control.
- Test locally with
curlorOpenIDdebug tools to retrieve a token and then call the collector endpoint with anAuthorization: Bearer <token>header to validate the end-to-end flow.
- Check the Windows Event Viewer and the application's stdout logs (enable
stdoutLogEnabledinweb.configtemporarily) for startup failures. - If the collector reports authentication failures, verify the
audienceandissuer_urlmatch the token contents. - Use
jwt.msorjwt.ioto decode tokens and inspect claims during development.
See the repository LICENSE file for license details.