Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<VersionPrefix>1.0.1</VersionPrefix>
<VersionPrefix>1.0.2</VersionPrefix>
<MinVerMinimumMajorMinor>1.0</MinVerMinimumMajorMinor>
<Company>RockSolidKnowledge</Company>
<WarningsAsErrors>CS1591;CS1570;CS1571;CS1572;CS1573;CS1574;CS1580;CS1581;CS1584;CS1587;CS1591;CS1658;CS1712;CS1734</WarningsAsErrors>
Expand Down
8 changes: 8 additions & 0 deletions NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,12 @@
<add key="IdentityServer Local" value="./nuget" />
<add key="NuGet" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<!-- <packageSourceMapping>
<packageSource key="IdentityServer Local">
<package pattern="Open.IdentityServer*" />
</packageSource>
<packageSource key="NuGet">
<package pattern="*" />
</packageSource>
</packageSourceMapping> -->
</configuration>
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ Open.IdentityServer enables the following features in your applications:
topics/deployment
topics/logging
topics/events
topics/open_telemetry
topics/crypto
topics/grant_types
topics/client_authentication
Expand Down
304 changes: 304 additions & 0 deletions docs/topics/open_telemetry.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
.. _refOpenTelemetry:

OpenTelemetry
=============

`OpenTelemetry <https://opentelemetry.io/>`_ is an open-source, vendor-neutral observability framework for generating, collecting, and exporting telemetry data (metrics, traces, and logs). It provides a standardised way to instrument applications, making it possible to monitor and troubleshoot distributed systems without being locked in to a particular observability vendor.

Open.IdentityServer provides built-in OpenTelemetry support through its ``ITelemetryService`` interface and ``DefaultTelemetryService`` implementation. Telemetry data is emitted automatically for key operations such as token issuance, client authentication, and request handling — with no additional configuration required to start collecting signals.

Overview
--------
OpenTelemetry defines three primary signal types:

- **Metrics** — Numerical measurements that describe the behaviour of your system over time (e.g. request counts, error rates, active connections).
- **Traces** — Records of the path a request takes through your system, broken into spans that represent individual units of work.
- **Logs** — Timestamped text records, enriched with structured data, that capture discrete events.

Open.IdentityServer emits metrics and traces natively using the .NET ``System.Diagnostics`` APIs (``Meter``, ``Counter``, ``ActivitySource``). Logging is handled through the standard ASP.NET Core ``ILogger`` infrastructure, which can be exported via OpenTelemetry's logging bridge.

Getting Started
^^^^^^^^^^^^^^^
OpenTelemetry signals are emitted by Open.IdentityServer automatically. To collect and export them, you need to configure the OpenTelemetry SDK in your host application.

Install the required NuGet packages:

.. code-block:: bash

dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol

Then configure the OpenTelemetry SDK in your ``Program.cs`` or ``Startup.cs``:

.. code-block:: csharp

using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using OpenTelemetry.Logs;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddIdentityServer()
// ... your IdentityServer configuration
;

builder.Services.AddOpenTelemetry()
.ConfigureResource(resource =>
{
resource.AddService("<Your IdentityServer application name>");
})
.WithMetrics(metrics =>
{
metrics
.AddMeter(TelemetryConstants.MetricsConstants.MeterName)
.AddOtlpExporter();
})
.WithTracing(tracing =>
{
tracing
.AddSource(TelemetryConstants.TraceCategories.Basic)
.AddSource(TelemetryConstants.TraceCategories.Cache)
.AddSource(TelemetryConstants.TraceCategories.Services)
.AddSource(TelemetryConstants.TraceCategories.Stores)
.AddSource(TelemetryConstants.TraceCategories.Validation)
.AddOtlpExporter();
});

builder.Logging.AddOpenTelemetry(logging =>
{
logging.AddOtlpExporter();
});

.. note::
The ``DefaultTelemetryService`` is registered as a singleton automatically when you call ``AddIdentityServer()``. No additional registration is needed to enable telemetry.

Metrics
-------
Open.IdentityServer exposes metrics through a .NET ``Meter`` named ``Open.IdentityServer``. All metric instruments are counters that track the volume and outcome of protocol operations.

Meter Name
^^^^^^^^^^
``Open.IdentityServer``

Available Instruments
^^^^^^^^^^^^^^^^^^^^^

.. list-table::
:header-rows: 1
:widths: 40 15 45

* - Instrument Name
- Type
- Description
* - ``tokenservice.operation``
- Counter
- Counts all operations, tagged with ``result`` (``success``, ``error``, or ``internal_error``), ``client``, and optionally ``error``.
* - ``tokenservice.active_requests``
- UpDownCounter
- Tracks the number of currently active IdentityServer protocol requests. Tagged with ``endpoint`` and ``path``.
* - ``tokenservice.api.secret_validation``
- Counter
- Counts API secret validation attempts. Tagged with ``api``, ``auth_method`` (on success), and ``error`` (on failure).
* - ``tokenservice.client.secret_validation``
- Counter
- Counts client secret validation attempts. Tagged with ``client``, ``auth_method`` (on success), and ``error`` (on failure).
* - ``tokenservice.client.config_validation``
- Counter
- Counts client configuration validation attempts. Tagged with ``client`` and ``error`` (on failure).
* - ``tokenservice.token_issued``
- Counter
- Counts tokens issued. Tagged with ``client``, ``grant_type``, and ``error`` (on failure).
* - ``tokenservice.introspection``
- Counter
- Counts token introspection requests. Tagged with ``caller``, ``active`` (token status), and ``error`` (on failure).
* - ``tokenservice.revocation``
- Counter
- Counts token revocation requests. Tagged with ``client`` and ``error`` (on failure).
* - ``tokenservice.device_authentication``
- Counter
- Counts device authentication requests. Tagged with ``client`` and ``error`` (on failure).
* - ``tokenservice.resourceowner_authentication``
- Counter
- Counts resource owner password authentication attempts. Tagged with ``client`` and ``error`` (on failure).
* - ``tokenservice.backchannel_authentication``
- Counter
- Counts backchannel (CIBA) authentication requests. Tagged with ``client`` and ``error`` (on failure). **Note:** CIBA is not yet implemented in Open.IdentityServer, but the metric is reserved for future use.
* - ``tokenservice.pushed_authorization_request``
- Counter
- Counts pushed authorization requests (PAR). Tagged with ``client`` and ``error`` (on failure). **Note:** PAR is not yet implemented in Open.IdentityServer, but the metric is reserved for future use.

Metric Tags
^^^^^^^^^^^^
Metrics are enriched with the following tags to enable filtering and grouping in your observability platform:

.. list-table::
:header-rows: 1
:widths: 20 80

* - Tag
- Description
* - ``result``
- The outcome of the operation: ``success``, ``error``, or ``internal_error``.
* - ``client``
- The client identifier associated with the operation.
* - ``error``
- A description of the error, present only when the operation failed.
* - ``endpoint``
- The logical endpoint handling the request (e.g. ``TokenEndpoint``).
* - ``path``
- The request path.
* - ``api``
- The API resource name (used in API secret validation).
* - ``auth_method``
- The authentication method used (e.g. ``client_secret_post``, ``private_key_jwt``).
* - ``caller``
- The caller of the introspection endpoint.
* - ``active``
- Whether the introspected token is active (``true``/``false``).
* - ``grant_type``
- The OAuth grant type used for token issuance.

Subscribing to Metrics
^^^^^^^^^^^^^^^^^^^^^^
To collect Open.IdentityServer metrics, subscribe to the ``Open.IdentityServer`` meter in your OpenTelemetry configuration:

.. code-block:: csharp

builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics.AddMeter(TelemetryConstants.MetricsConstants.MeterName);
});

Traces
------
Open.IdentityServer uses .NET ``ActivitySource`` instances to create distributed trace spans. Traces provide visibility into the internal processing of each request, helping you identify performance bottlenecks and understand the flow of operations.

Activity Sources
^^^^^^^^^^^^^^^^
Open.IdentityServer defines several activity sources, each representing a category of operations:

.. list-table::
:header-rows: 1
:widths: 40 60

* - Activity Source Name
- Description
* - ``Open.IdentityServer``
- Top-level protocol request processing (e.g. the overall handling of a token or authorize request).
* - ``Open.IdentityServer.Cache``
- Caching operations (cache reads, writes, and invalidations).
* - ``Open.IdentityServer.Services``
- Internal service operations (token creation, consent, key material, etc.).
* - ``Open.IdentityServer.Stores``
- Data store operations (reading/writing grants, clients, resources).
* - ``Open.IdentityServer.Validation``
- Validation operations (token validation, request validation, secret validation).

Subscribing to Traces
^^^^^^^^^^^^^^^^^^^^^
To collect traces, add the relevant activity sources to your OpenTelemetry tracing configuration:

.. code-block:: csharp

builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
// Subscribe to all Open.IdentityServer activity sources
tracing
.AddSource(TelemetryConstants.TraceCategories.Basic)
.AddSource(TelemetryConstants.TraceCategories.Cache)
.AddSource(TelemetryConstants.TraceCategories.Services)
.AddSource(TelemetryConstants.TraceCategories.Stores)
.AddSource(TelemetryConstants.TraceCategories.Validation);
});

You can subscribe to a subset of sources if you only need visibility into specific categories. For example, to trace only store operations:

.. code-block:: csharp

builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing.AddSource(TelemetryConstants.TraceCategories.Stores);
});

Trace Granularity
^^^^^^^^^^^^^^^^^
Each trace activity is named after the class and method performing the operation, providing fine-grained visibility. For example, a token request might produce a trace hierarchy such as:

::

Open.IdentityServer: IdentityServerProtocolRequest
└─ Open.IdentityServer: TokenEndpoint.ProcessAsync
└─ Open.IdentityServer.Validation: ClientSecretValidator.ValidateAsync
└─ Open.IdentityServer.Validation: TokenRequestValidator.ValidateRequestAsync
└─ Open.IdentityServer.Stores: DefaultRefreshTokenStore.GetRefreshTokenAsync
└─ Open.IdentityServer.Services: DefaultTokenService.CreateAccessTokenAsync

Logging
-------
Open.IdentityServer uses the standard ASP.NET Core ``ILogger`` infrastructure for structured logging. Log messages are emitted at various levels throughout the processing pipeline, providing detailed diagnostic information.

To export logs via OpenTelemetry, configure the logging bridge:

.. code-block:: csharp

builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.IncludeScopes = true;
logging.AddOtlpExporter();
});

For more details on log levels and filtering, see the :ref:`Logging <refLogging>` documentation page.

.. note::
If using Serilog, you will need to use the `OpenTelemetry Serilog Sink <https://github.com/serilog/serilog-sinks-opentelemetry>`_ to forward logs to OpenTelemetry. The built-in logging bridge does not support Serilog directly.

Exporters
---------
OpenTelemetry supports a wide variety of exporters for sending telemetry data to your chosen backend. Common choices include:

- **OTLP (OpenTelemetry Protocol)** — The standard protocol, supported by most observability platforms (e.g. Jaeger, Grafana, Datadog, Azure Monitor, AWS X-Ray).
- **Prometheus** — For metrics scraping (use ``OpenTelemetry.Exporter.Prometheus.AspNetCore``).
- **Console** — Useful during development (use ``OpenTelemetry.Exporter.Console``).

Example using the Console exporter for development:

.. code-block:: csharp

builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics
.AddMeter("Open.IdentityServer")
.AddConsoleExporter();
})
.WithTracing(tracing =>
{
tracing
.AddSource("Open.IdentityServer")
.AddSource("Open.IdentityServer.Cache")
.AddSource("Open.IdentityServer.Services")
.AddSource("Open.IdentityServer.Stores")
.AddSource("Open.IdentityServer.Validation")
.AddConsoleExporter();
});

Customisation
-------------
The ``ITelemetryService`` interface can be replaced with a custom implementation if you need to modify or extend the telemetry behaviour. Register your custom implementation before calling ``AddIdentityServer()``:

.. code-block:: csharp

builder.Services.AddSingleton<ITelemetryService, MyCustomTelemetryService>();

builder.Services.AddIdentityServer()
// ...
;

Since the default implementation is registered with ``TryAddSingleton``, any prior registration will take precedence.

.. note::
In most cases, the default implementation combined with OpenTelemetry SDK configuration provides sufficient flexibility without needing a custom ``ITelemetryService``.
2 changes: 1 addition & 1 deletion src/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ExtensionsVersion>10.0.5</ExtensionsVersion>
<EntityFrameworkVersion>10.0.5</EntityFrameworkVersion>

<IdentityServerVersion>1.0.1-*</IdentityServerVersion>
<IdentityServerVersion>1.0.2-*</IdentityServerVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
14 changes: 13 additions & 1 deletion src/EntityFramework.Storage/src/Stores/ClientStore.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Modified by Rock Solid Knowledge Ltd. Copyright in modifications 2026, Rock Solid Knowledge Ltd.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.


Expand All @@ -11,6 +12,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Open.IdentityServer.EntityFramework.Mappers;
using Open.IdentityServer.Services;

namespace Open.IdentityServer.EntityFramework.Stores;

Expand All @@ -25,6 +27,11 @@ public class ClientStore : IClientStore
/// </summary>
protected readonly IConfigurationDbContext Context;

/// <summary>
/// The telemetry.
/// </summary>
protected readonly ITelemetryService Telemetry;

/// <summary>
/// The logger.
/// </summary>
Expand All @@ -34,11 +41,13 @@ public class ClientStore : IClientStore
/// Initializes a new instance of the <see cref="ClientStore"/> class.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="telemetry">The telemetry service.</param>
/// <param name="logger">The logger.</param>
/// <exception cref="ArgumentNullException">context</exception>
public ClientStore(IConfigurationDbContext context, ILogger<ClientStore> logger)
public ClientStore(IConfigurationDbContext context, ITelemetryService telemetry, ILogger<ClientStore> logger)
{
Context = context ?? throw new ArgumentNullException(nameof(context));
Telemetry = telemetry;
Logger = logger;
}

Expand All @@ -51,6 +60,9 @@ public ClientStore(IConfigurationDbContext context, ILogger<ClientStore> logger)
/// </returns>
public virtual async Task<Client> FindClientByIdAsync(string clientId)
{
using var trace = Telemetry
.Trace(TelemetryConstants.TraceCategories.Stores, this);

IQueryable<Entities.Client> baseQuery = Context.Clients
.Where(x => x.ClientId == clientId);

Expand Down
Loading
Loading