diff --git a/astro/src/components/LogLevel.astro b/astro/src/components/LogLevel.astro new file mode 100644 index 000000000..b7d3988b1 --- /dev/null +++ b/astro/src/components/LogLevel.astro @@ -0,0 +1,35 @@ +--- +// LogLevel.astro +// Renders a log level name with the appropriate color from the spectrum +// Uses mode-aware colors for optimal contrast in light and dark themes + +interface Props { + level: 'Trace' | 'Debug' | 'Information' | 'Warning' | 'Error' | 'Critical'; +} + +const { level } = Astro.props; +--- + +{level} + + diff --git a/astro/src/components/LogLevelSpectrum.astro b/astro/src/components/LogLevelSpectrum.astro new file mode 100644 index 000000000..910aa6fe4 --- /dev/null +++ b/astro/src/components/LogLevelSpectrum.astro @@ -0,0 +1,307 @@ + +--- +// LogLevelSpectrum.astro +// Visual anxiety-spectrum bar for log levels with quick-reference table +--- + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelUrgencyAction
TraceDev onlySupport-requested diagnostics only. Contains sensitive data.
DebugDev/StagingEnable in dev/staging. Disable before production. May contain sensitive data.
InformationMonitorNormal operations. Good default for production.
WarningInvestigateReview when convenient. May indicate misconfiguration.
ErrorAct soonInvestigate promptly. Something failed.
CriticalAct now!Act immediately. System may be down.
+
+ + diff --git a/astro/src/content/docs/accesstokenmanagement/advanced/logging.md b/astro/src/content/docs/accesstokenmanagement/advanced/logging.md deleted file mode 100644 index 5f12dd386..000000000 --- a/astro/src/content/docs/accesstokenmanagement/advanced/logging.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: "Logging" -description: "Documentation for logging configuration and usage in Duende Access Token Management, including log levels and Serilog setup" -date: 2026-01-19 -sidebar: - order: 50 ---- - -Duende Access Token Management uses the standard logging facilities provided by ASP.NET Core. You generally do not need to perform any extra configuration, as it will use the logging provider you have already configured for your application. - -For general information on how to configure logging, setting up Serilog, and understanding log levels in Duende products, see our [Logging Fundamentals](/general/logging.md) guide. - -The Microsoft [documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging) has a good introduction and description of the built-in logging providers. - -## Log Levels - -You can control the log output for Duende Access Token Management specifically by configuring the `Duende.AccessTokenManagement` namespace in your logging configuration. -For example, to enable debug logging for Access Token Management while keeping other logs at a higher level, you can modify your `appsettings.json`: - -```json -// appsettings.json -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Duende.AccessTokenManagement": "Debug" - } - } -} -``` \ No newline at end of file diff --git a/astro/src/content/docs/accesstokenmanagement/advanced/logging.mdx b/astro/src/content/docs/accesstokenmanagement/advanced/logging.mdx new file mode 100644 index 000000000..03340cb42 --- /dev/null +++ b/astro/src/content/docs/accesstokenmanagement/advanced/logging.mdx @@ -0,0 +1,420 @@ +--- +title: "Logging" +description: "Documentation for logging configuration and usage in Duende Access Token Management, including log levels and Serilog setup" +date: 2026-01-19 +sidebar: + order: 50 +--- + +import { LinkCard } from '@astrojs/starlight/components'; +import LogLevel from '~/components/LogLevel.astro'; + +Duende Access Token Management uses the standard logging facilities provided by ASP.NET Core. You generally do not need to perform any extra configuration, as it will use the logging provider you have already configured for your application. + +For log level definitions, environment guidance, and actionable next steps for each level, see the [Logging Fundamentals](/general/logging) guide. + + + +## Configuration + +Logs are written under the `Duende.AccessTokenManagement` category. To control log output for Access Token Management specifically, set that namespace in your `appsettings.json`: + +```json +// appsettings.json +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Duende.AccessTokenManagement": "Debug" + } + } +} +``` + +:::tip +The Microsoft [logging documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging) has a good introduction to the built-in logging providers and how to configure them. +::: + +## What Gets Logged + +Access Token Management emits structured log messages across several functional areas. Each message includes contextual parameters (client ID, URL, error details, etc.) for effective filtering and troubleshooting. + +### User Token Acquisition + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
Cannot authenticate scheme: `{Scheme}` to acquire user access tokenAuthentication failed for the specified scheme
Authentication result properties are null for scheme: `{Scheme}` after authenticationSuccessful authentication but no token properties returned
Failed to get a UserToken because no tokens found in cookie properties`SaveTokens` must be enabled for automatic token refresh
Starting user token acquisitionBeginning the user token retrieval process
Cannot retrieve token: No active userNo authenticated user context available
Cannot retrieve token: No token data found in user token store for user `{User}`User exists but has no stored tokens
+ +### Token Refresh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
No refresh token found in user token store for user `{User}` / resource `{Resource}`. Returning current access tokenNo refresh token available; returning existing access token
No access token found in user token store for user `{User}` / resource `{Resource}`. Trying to refreshMissing access token; attempting refresh
Token for user `{User}` will be refreshed. Expiration: `{Expiration}`, ForceRenewal: `{ForceRenewal}`Token refresh triggered by expiration or explicit force
Refreshing access token using refresh token: hash=`{TokenHash}`Executing refresh token grant (token hashed for security)
Sending Refresh token request to: `{Url}`HTTP request to token endpoint
Returning refreshed token for user: `{User}`Refresh succeeded
Returning current token for user: `{User}`Using cached token (still valid)
Error refreshing access token. Error = `{Error}`, Description: `{ErrorDescription}`Refresh failed with OAuth error
Access Token of type `{TokenType}` refreshed with expiration: `{Expiration}`Successful refresh with new expiration
+ +### Token Revocation + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
Revoking refresh token: hash=`{TokenHash}`Starting revocation (token hashed)
Sending Token revocation request to: `{Url}`HTTP request to revocation endpoint
Error revoking refresh token. Error = `{Error}`Revocation failed
+ +### Client Credentials + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
Requesting client credentials access token at endpoint: `{Url}`Starting client credentials grant
Client Credentials token of type `{TokenType}` for Client: `{ClientName}` retrieved with expiration `{Expiration}`Token successfully obtained
Error requesting access token for client `{ClientName}`. Error = `{Error}`, Description: `{ErrorDescription}`Token request failed
Caching access token for client: `{ClientName}`. Expiration: `{Expiration}`Storing token in cache
Cache hit for obtaining access token for client: `{ClientName}`Using cached token
Cache miss while retrieving access token for client: `{ClientName}`No cached token; fetching new one
Will not cache token result with error for `{ClientName}`. Error = `{Error}`, Description: `{ErrorDescription}`Skipping cache for failed token
An exception has occurred while reading ClientCredentialsToken value from the cache for client `{ClientName}`Cache read error; falling back to fetch
Error trying to set token in cache for client `{ClientName}`Cache write failed
Error parsing cached access token for client `{ClientName}`Cached value was corrupted
Failed to obtain token from cache for client `{ClientName}` using cacheKey `{CacheKey}`. Will obtain new tokenCache retrieval failed; fetching new token
+ +### Request Handler + +These messages are emitted by `AccessTokenRequestHandler` when sending HTTP requests with tokens: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
Sending Access token of type `{TokenType}` to endpoint: `{Url}`Attaching token to outgoing request
Failed to obtain an access token while sending the request. Error: `{Error}`, ErrorDescription `{ErrorDescription}`Could not get token; request sent without authentication
While sending a request, received UnAuthorized after acquiring a new access tokenFresh token was rejected by the resource server
Token not accepted while sending request. Retrying with new access token401 response triggered token refresh and retry
+ +### DPoP (Demonstrating Proof-of-Possession) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
Creating DPoP proof token for token requestGenerating DPoP proof for token endpoint
Sending DPoP proof token in request to endpoint: `{Url}`Attaching DPoP proof to request
Failed to create DPoP proof token for request to endpoint: `{Url}`DPoP proof generation failed; falling back to Bearer
The authorization server has supplied a new nonce on a successful responseServer-provided nonce stored for future requests
DPoP nonce error: `{Error}`. Retrying using new nonceRetrying with server-provided nonce
DPoP error `{Error}` during token refresh. Retrying with server nonceNonce error during refresh; retrying
Failed to get DPoP Nonce because server didn't respond with ok. StatusCode was: `{StatusCode}`Nonce request failed
Cache hit for DPoP nonce for URL: `{Url}`, method: `{Method}`Using cached nonce
Writing DPoP nonce to Cache for URL: `{Url}`, method: `{Method}`. Expiration: `{Expiration}`Storing nonce in cache
Cache miss for DPoP nonce for URL: `{Url}`, method: `{Method}`No cached nonce available
Failed to parse the cached Nonce `{Value}` for URL: `{Url}`, method: `{Method}`. Error: `{Error}`Cached nonce was invalid
+ +### Key Parsing + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
Failed to parse JsonWebKeyJWK parsing failed
Failed to create thumbprint from JSON web keyCould not compute key thumbprint
+ +## OpenTelemetry Integration + +Access Token Management supports [OpenTelemetry](https://opentelemetry.io/) for distributed tracing and metrics collection. + +### Tracing + +The library emits traces under the activity source `Duende.AccessTokenManagement`. Add this to your OpenTelemetry configuration: + +```csharp +builder.Services.AddOpenTelemetry() + .WithTracing(tracing => tracing + .AddSource("Duende.AccessTokenManagement") + // ... other sources + ); +``` + +**Activity spans:** + +| Name | Description | +|------|-------------| +| `Duende.AccessTokenManagement.AcquiringToken` | Wraps the entire token acquisition operation | + +### Metrics + +Metrics are exposed under the meter `Duende.AccessTokenManagement`: + +```csharp +builder.Services.AddOpenTelemetry() + .WithMetrics(metrics => metrics + .AddMeter("Duende.AccessTokenManagement") + // ... other meters + ); +``` + +**Available counters:** + +| Counter | Description | Tags | +|---------|-------------|------| +| `access_token_used` | Number of times an access token was used | `ClientId`, `TokenType` | +| `token_retrieved` | Number of times a token was retrieved from the token endpoint | `ClientId`, `TokenType` | +| `token_retrieval_failed` | Number of times token retrieval failed | `ClientId`, `TokenType`, `Error` | +| `token_send_retry` | Number of times a token was rejected and retried | `ClientId` | +| `dpop_nonce_error_retry` | Number of times a DPoP nonce error triggered a retry | `ClientId`, `Error` | + +The `TokenType` tag distinguishes between `ClientCredentials` and `User` token flows. diff --git a/astro/src/content/docs/general/logging.md b/astro/src/content/docs/general/logging.md deleted file mode 100644 index 7cfed874e..000000000 --- a/astro/src/content/docs/general/logging.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -title: "Logging Fundamentals" -description: "General guidance on configuring logging for Duende Software products using Microsoft.Extensions.Logging and Serilog." -date: 2026-01-19 -sidebar: - order: 10 ---- - -All Duende Software products (IdentityServer, Backend for Frontend (BFF), Access Token Management, etc.) use the standard logging facilities provided by ASP.NET Core (`Microsoft.Extensions.Logging`). -This means they integrate seamlessly with whatever logging provider you choose for your application. - -This guide provides general instructions for setting up logging that apply to all our products. - -## Log Levels - -We adhere to the standard Microsoft guidelines for log levels. Understanding these levels helps you configure the appropriate verbosity for your environment. - -* **`Trace`** - * **Usage:** Extremely detailed information for troubleshooting complex issues. - * **Production:** **Do not enable** in production unless specifically instructed for diagnostics. May contain sensitive data (e.g., token hashes, PII). -* **`Debug`** - * **Usage:** Internal flow details, useful for understanding _why_ a decision was made (e.g., policy evaluation, token validation steps). - * **Production:** Generally disabled in production, but safe to enable temporarily for deeper investigation. -* **`Information`** - * **Usage:** High-level events tracking the general flow (e.g., "Request started", "Token issued"). - * **Production:** Often the default level for production. -* **`Warning`** - * **Usage:** Unexpected events that didn't stop the application but might require investigation (e.g., "Invalid client configuration detected"). -* **`Error`** - * **Usage:** Exceptions and errors that cannot be handled gracefully. -* **`Critical`** - * **Usage:** Failures that require immediate attention (e.g., "Signing key not found"). - -## Setup for Microsoft.Extensions.Logging - -This is the default logging provider for ASP.NET Core. If you haven't configured a third-party logger, this is what you are using. - -You can configure log levels in your `appsettings.json` file. To get detailed logs from Duende products, you often want to set the `Duende` namespace (or specific sub-namespaces) to `Debug`. - -```json -// appsettings.json -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information", - // Enable Debug logs for all Duende products - "Duende": "Debug" - } - } -} -``` - -## Setup for Serilog - -[Serilog](https://serilog.net) is a popular structured logging library for .NET. We highly recommend it for its flexibility and rich sink ecosystem (Console, File, Seq, Elasticsearch, etc.). - -### 1. Installation - -Install the necessary packages: - -```bash -dotnet add package Serilog.AspNetCore -``` - -### 2. Configuration In `Program.cs` - -Configure Serilog early in your application startup to capture all logs, including startup errors. - -```csharp -// Program.cs -using Serilog; - -var builder = WebApplication.CreateBuilder(args); - -// Configure Serilog -builder.Host.UseSerilog((ctx, lc) => lc - .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}") - .Enrich.FromLogContext() - .ReadFrom.Configuration(ctx.Configuration)); - -var app = builder.Build(); - -app.UseSerilogRequestLogging(); // Optional: cleaner HTTP request logging - -// ... rest of your pipeline -``` - -### 3. Configuration In `appsettings.json` - -You can then control log levels via `appsettings.json`. This approach allows you to change log levels without recompiling your code. - -```json -{ - "Serilog": { - "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information", - "System": "Warning", - // Enable detailed logging for Duende products - "Duende": "Debug" - } - } - } -} -``` - -## Troubleshooting Specific Products and Components - -If you are debugging a specific component, you can target its namespace to reduce noise. - -| Product | Namespace | -|-----------------------------|--------------------------------| -| **IdentityServer** | `Duende.IdentityServer` | -| **BFF** | `Duende.Bff` | -| **User Management** | `Duende.UserManagement` | -| **Access Token Management** | `Duende.AccessTokenManagement` | - -Example `appsettings.json` for debugging only BFF interactions: - -```json -"Duende.Bff": "Debug", -"Duende.IdentityServer": "Information" -``` diff --git a/astro/src/content/docs/general/logging.mdx b/astro/src/content/docs/general/logging.mdx new file mode 100644 index 000000000..5a08ec866 --- /dev/null +++ b/astro/src/content/docs/general/logging.mdx @@ -0,0 +1,288 @@ +--- +title: "Logging Fundamentals" +description: "General guidance on configuring logging for Duende Software products using Microsoft.Extensions.Logging and Serilog." +date: 2026-01-19 +sidebar: + order: 10 +--- + +import LogLevelSpectrum from '~/components/LogLevelSpectrum.astro'; +import { LinkCard, CardGrid } from '@astrojs/starlight/components'; + +All Duende Software products ([IdentityServer](/identityserver/), [Backend for Frontend (BFF)](/bff/), [Access Token Management](/accesstokenmanagement/), etc.) use the standard logging facilities provided by ASP.NET Core (`Microsoft.Extensions.Logging`). +This means they integrate seamlessly with whatever logging provider you choose for your application. + +This guide provides general instructions for setting up logging that apply to all our products. + +:::danger[Sensitive data in logs] +**`Trace` and `Debug` logs may contain sensitive information**, including token values, token hashes, and personally identifiable information (PII). +Never enable these levels in production unless you are actively diagnosing an issue under controlled conditions and have taken steps to secure your log output. +::: + +## Log Levels + +We follow the [standard Microsoft guidelines for log levels](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging#log-level). The spectrum below shows where each level sits on the operational urgency scale, with a quick action guide for each. + + + +Scroll down for detailed guidance on what each level means, who it affects, and what you should do when you see it. + +### Trace + +**Meaning:** Extremely detailed diagnostic information intended for developers debugging complex, hard-to-reproduce issues. + +**Customer impact:** None directly. Trace is never enabled in production under normal circumstances. + +**Action:** +1. Do **not** enable in production unless Duende Support explicitly requests it. +2. If you must enable it, use a scoped namespace (e.g., `Duende.IdentityServer`) to limit output. +3. Secure and rotate your logs immediately after capturing diagnostics. +4. Disable as soon as the issue is diagnosed. + +**Example:** +``` +[Trace] Duende.IdentityServer.Validation.TokenValidator + Validating JWT token: eyJhbGciOiJSUzI1NiIs... +``` + +--- + +### Debug + +**Meaning:** Internal flow details: why decisions were made, which code paths were taken (e.g., policy evaluation, token validation steps). + +**Customer impact:** None directly. Debug is for developer understanding, not user-facing operations. + +**Action:** +1. Enable during local development or staging to understand application behavior. +2. Use `appsettings.Development.json` to isolate Debug logging from production config. +3. Disable before deploying to production, or set an expiry reminder. + +**Example:** +``` +[Debug] Duende.IdentityServer.ResponseHandling.AuthorizeResponseGenerator + Creating authorization code response for client 'spa-app' +``` + +--- + +### Information + +**Meaning:** High-level events that track the normal flow of the application: requests starting, tokens issued, sessions created. + +**Customer impact:** Minimal. These are expected events. Absence of expected Information logs may indicate a problem. + +**Action:** +1. No immediate action required. This is normal operational noise. +2. Use Information logs for auditing user activity and correlating requests by ID. +3. This is often the recommended default level for production. + +**Example:** +``` +[Information] Duende.IdentityServer.Hosting.IdentityServerMiddleware + Invoking IdentityServer endpoint: /connect/token (TokenEndpoint) +``` + +--- + +### Warning + +**Meaning:** Unexpected events that did not stop the application, but may indicate misconfiguration, an edge case, or degraded behavior. + +**Customer impact:** Possible. Some users may be experiencing issues. Investigate to confirm impact. + +**Action:** +1. Review the warning message and context (correlation ID, client ID, user). +2. Check if the warning is recurring or isolated. Recurring warnings deserve prompt attention. +3. Common causes: invalid client configuration, deprecated settings, transient infrastructure issues. +4. If in doubt, open a support ticket with Duende. + +**Example:** +``` +[Warning] Duende.IdentityServer.Validation.ClientSecretValidator + Client secret validation failed for client 'legacy-app' +``` + +--- + +### Error + +**Meaning:** An operation failed and could not recover. An exception was thrown and not handled gracefully. + +**Customer impact:** Likely. A user request probably failed. Investigate promptly. + +**Action:** +1. Check the full stack trace in your log sink. +2. Correlate with the request ID or user subject ID to identify scope. +3. Determine if the error is recurring or isolated. +4. If recurring: escalate to your team and open a Duende Support ticket if needed. +5. Check whether downstream dependencies (database, external IdP) are healthy. + +**Example:** +``` +[Error] Duende.IdentityServer.Validation.TokenRequestValidator + Failed validation of token request: invalid_grant +``` + +--- + +### Critical + +**Meaning:** A catastrophic failure that requires immediate attention. The system may be partially or fully unable to function. + +**Customer impact:** High. Users are likely unable to authenticate or obtain tokens. + +**Action:** +1. **Act immediately.** Page your on-call team. +2. Check startup logs. Critical events often occur at startup (missing signing key, missing store implementation). +3. Verify database connectivity and key material availability. +4. Review deployment changes made immediately before the issue started. +5. Contact [Duende Support](https://duendesoftware.com/support) with your logs if the cause is unclear. + +**Example:** +``` +[Critical] Duende.IdentityServer.Startup + No signing key material found. IdentityServer cannot issue tokens. +``` + +--- + +## Environment Configuration + +Use this table as a quick reference for which log levels to enable in each environment: + +| Level | Development | Staging | Production | +|-------|-------------|---------|------------| +| **Trace** | ⚠️ Temporarily, for active investigations | ❌ Disable | ❌ Disable (Enable under extreme circumstances only) | +| **Debug** | ✅ Recommended | ⚠️ Temporarily, for active investigations | ❌ Disable | +| **Information** | ✅ | ✅ Recommended | ⚠️ Temporarily, for active investigations | +| **Warning** | ✅ | ✅ | ✅ Recommended | +| **Error** | ✅ | ✅ | ✅ | +| **Critical** | ✅ | ✅ | ✅ (with alerts) | + +:::tip +In production, set your minimum log level to `Warning` to reduce volume while still capturing actionable events. +Drop to `Information` when investigating a reported issue, and back to `Warning` when resolved. +::: + +## Setup for Microsoft.Extensions.Logging + +This is the default logging provider for ASP.NET Core. If you haven't configured a third-party logger, this is what you are using. + +You can configure log levels in your `appsettings.json` file. To get detailed logs from Duende products, you often want to set the `Duende` namespace (or specific sub-namespaces) to `Debug`. + +```json +// appsettings.json +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + // Enable Debug logs for all Duende products + "Duende": "Debug" + } + } +} +``` + +## Setup for Serilog + +[Serilog](https://serilog.net) is a popular structured logging library for .NET. We highly recommend it for its flexibility and rich sink ecosystem (Console, File, Seq, Elasticsearch, etc.). + +### 1. Installation + +Install the necessary packages: + +```bash +dotnet add package Serilog.AspNetCore +``` + +### 2. Configuration In `Program.cs` + +Configure Serilog early in your application startup to capture all logs, including startup errors. + +```csharp +// Program.cs +using Serilog; + +var builder = WebApplication.CreateBuilder(args); + +// Configure Serilog +builder.Host.UseSerilog((ctx, lc) => lc + .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}") + .Enrich.FromLogContext() + .ReadFrom.Configuration(ctx.Configuration)); + +var app = builder.Build(); + +app.UseSerilogRequestLogging(); // Optional: cleaner HTTP request logging + +// ... rest of your pipeline +``` + +### 3. Configuration In `appsettings.json` + +You can then control log levels via `appsettings.json`. This approach allows you to change log levels without recompiling your code. + +```json +{ + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "System": "Warning", + // Enable detailed logging for Duende products + "Duende": "Debug" + } + } + } +} +``` + +## Troubleshooting Specific Products and Components + +If you are debugging a specific component, you can target its namespace to reduce noise. + +| Product | Namespace | +|-----------------------------|--------------------------------| +| **IdentityServer** | `Duende.IdentityServer` | +| **BFF** | `Duende.Bff` | +| **User Management** | `Duende.UserManagement` | +| **Access Token Management** | `Duende.AccessTokenManagement` | + +Example `appsettings.json` for debugging only BFF interactions: + +```json +"Duende.Bff": "Debug", +"Duende.IdentityServer": "Information" +``` + +## Product-Specific Guides + +Each Duende product has its own logging page with product-specific configuration namespaces, key events to watch for, and advanced topics. + + + + + + + diff --git a/astro/src/content/docs/identitymodel-oidcclient/logging.md b/astro/src/content/docs/identitymodel-oidcclient/logging.md deleted file mode 100644 index 980f0305a..000000000 --- a/astro/src/content/docs/identitymodel-oidcclient/logging.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: OIDC Client Logging -description: Learn how to configure and customize logging in OidcClient using Microsoft.Extensions.Logging.ILogger -sidebar: - label: Logging - order: 4 -redirect_from: - - /foss/identitymodel.oidcclient/logging/ ---- - -`OidcClient` logs errors, warnings, and diagnostic information using -`Microsoft.Extensions.Logging.ILogger`, the standard .NET logging library. - -You can use any logging provider to store your logs however you like, -by setting the `LoggerFactory` property on `OidcClientOptions`: - -```csharp {9,17} -// Program.cs -using Duende.IdentityModel; -using Duende.IdentityModel.OidcClient; - -var builder = Host.CreateApplicationBuilder(args); - -builder.Services.AddSingleton(svc => -{ - var loggerFactory = svc.GetRequiredService(); - var options = new OidcClientOptions - { - Authority = "https://demo.duendesoftware.com", - ClientId = "interactive.public", - Scope = "openid profile email offline_access", - RedirectUri = "app://localhost/", - PostLogoutRedirectUri = "app://localhost/", - LoggerFactory = loggerFactory - }; - return new OidcClient(options); -}); - -var app = builder.Build(); -var client = app.Services.GetService(); -``` - -Using this approach, you can use other logging frameworks, like [Serilog](https://github.com/serilog/serilog-extensions-hosting) for example. - -For general information on how to configure logging in .NET applications, see our [Logging Fundamentals](/general/logging.md) guide. - -## Log Levels - -The `OidcClient` logs at the following levels: - -- `Trace` -- `Debug` -- `Information` -- `Error` - -You can set the log level in your `appsettings.json` by modifying the following snippet. - -```json -// appsettings.json -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information", - "Duende.IdentityModel.OidcClient": "Error" - } - } -} -``` diff --git a/astro/src/content/docs/identitymodel-oidcclient/logging.mdx b/astro/src/content/docs/identitymodel-oidcclient/logging.mdx new file mode 100644 index 000000000..0b98104dd --- /dev/null +++ b/astro/src/content/docs/identitymodel-oidcclient/logging.mdx @@ -0,0 +1,380 @@ +--- +title: OIDC Client Logging +description: Learn how to configure and customize logging in OidcClient using Microsoft.Extensions.Logging.ILogger +sidebar: + label: Logging + order: 4 +redirect_from: + - /foss/identitymodel.oidcclient/logging/ +--- + +import { LinkCard } from '@astrojs/starlight/components'; +import LogLevel from '~/components/LogLevel.astro'; + +`OidcClient` logs errors, warnings, and diagnostic information using +`Microsoft.Extensions.Logging.ILogger`, the standard .NET logging library. + +For log level definitions, environment guidance, and actionable next steps for each level, see the [Logging Fundamentals](/general/logging) guide. + + + +## Configuration + +### Wiring Up a Logger Factory + +`OidcClient` does not use the ASP.NET Core dependency injection container directly — instead, you configure it by setting the `LoggerFactory` property on `OidcClientOptions`. This gives you full control over logging in native app, mobile, and console scenarios. + +```csharp {9,17} +// Program.cs +using Duende.IdentityModel; +using Duende.IdentityModel.OidcClient; + +var builder = Host.CreateApplicationBuilder(args); + +builder.Services.AddSingleton(svc => +{ + var loggerFactory = svc.GetRequiredService(); + var options = new OidcClientOptions + { + Authority = "https://demo.duendesoftware.com", + ClientId = "interactive.public", + Scope = "openid profile email offline_access", + RedirectUri = "app://localhost/", + PostLogoutRedirectUri = "app://localhost/", + LoggerFactory = loggerFactory + }; + return new OidcClient(options); +}); + +var app = builder.Build(); +var client = app.Services.GetService(); +``` + +You can use any logging framework that integrates with `ILoggerFactory`, such as [Serilog](https://github.com/serilog/serilog-extensions-hosting). + +### Log Level Configuration + +`OidcClient` emits logs at `Trace`, `Debug`, `Information`, and `Error` levels. To control log output, set the `Duende.IdentityModel.OidcClient` namespace in your `appsettings.json`: + +```json +// appsettings.json +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "Duende.IdentityModel.OidcClient": "Error" + } + } +} +``` + +## What Gets Logged + +OidcClient emits structured log messages across several functional areas. Each message includes contextual parameters for effective filtering and troubleshooting. + +### Login Flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
LoginAsyncBeginning the login method
Starting authentication request.Login flow initiated
Authentication request success.Login completed successfully
PrepareLoginAsyncPreparing login state for manual flow
CreateAuthorizeStateAsyncCreating PKCE and state parameters
The IdentityProvider contains a pushed authorization request endpoint. Automatically pushing authorization parameters. Use DisablePushedAuthorization to opt out.PAR endpoint detected and being used
Failed to push authorization parametersPAR request failed
CreateAuthorizeUrlBuilding the authorization URL
CreateAuthorizeParametersAssembling authorize request parameters
AuthorizeAsyncStarting browser-based authorization
+ +### Response Processing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
ProcessResponseAsyncBeginning response processing
Processing response.Handling authorization response
Authorize response: `{Response}`Raw authorization response data
ProcessCodeFlowResponseAsyncProcessing authorization code flow
RedeemCodeAsyncExchanging code for tokens
ValidateTokenResponseValidating token endpoint response
`{Error}`Authorization or token response error
+ +### Discovery Document + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
EnsureProviderInformationChecking provider configuration
Skipping refresh of discovery document.Reusing cached discovery document
Successfully loaded discovery documentDiscovery document retrieved
Loaded keyset from `{JwksUri}`JSON Web Key Set location
Keyset contains the following kids: `{Kids}`Available signing key IDs
Error loading discovery document: `{ErrorType}` - `{Error}`Discovery document retrieval failed
Issuer name is missing in provider informationInvalid provider configuration
Authorize endpoint is missing in provider informationInvalid provider configuration
Token endpoint is missing in provider informationInvalid provider configuration
Key set is missing in provider informationInvalid provider configuration (when required)
+ +### UserInfo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
GetUserInfoAsyncStarting userinfo request
Error contacting userinfo endpoint: `{Error}`Userinfo request failed
sub claim is missing from userinfo endpointUserinfo response missing required claim
sub claim from userinfo endpoint is different than sub claim from identity token.Subject mismatch between tokens
+ +### Token Refresh + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
RefreshTokenAsyncStarting token refresh
Failed on RefreshTokensAsync: `{Error}` - `{Description}`Automatic token refresh failed (RefreshTokenDelegatingHandler)
+ +### Logout + + + + + + + + + + + + + + + + +
LevelMessageDescription
CreateEndSessionUrlBuilding the end session URL
+ +### Claims Processing + + + + + + + + + + + + + + + + + + + + + +
LevelMessageDescription
ProcessClaimsMerging claims from tokens and userinfo
Claim: `{Type}`: `{Value}`Individual claim being processed
+ +### Configuration + + + + + + + + + + + + + + + + +
LevelMessageDescription
Effective options:Followed by serialized OidcClientOptions
+ +:::tip[Sensitive Data] +At `Trace` level, the full `OidcClientOptions` configuration is serialized to logs, which can help diagnose configuration issues. Be cautious with `Trace` logging in production as it may expose sensitive configuration details. +::: diff --git a/astro/src/content/docs/identityserver/diagnostics/logging.md b/astro/src/content/docs/identityserver/diagnostics/logging.md deleted file mode 100644 index 0e3ba99fc..000000000 --- a/astro/src/content/docs/identityserver/diagnostics/logging.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -title: "Logging" -description: "Documentation for logging configuration and usage in Duende IdentityServer, including log levels and Serilog setup" -date: 2020-09-10T08:22:12+02:00 -sidebar: - order: 10 -redirect_from: - - /identityserver/v5/diagnostics/logging/ - - /identityserver/v6/diagnostics/logging/ - - /identityserver/v7/diagnostics/logging/ ---- - -Duende IdentityServer uses the standard logging facilities provided by ASP.NET Core. You don't need to do any extra configuration to benefit from rich logging functionality. - -For general information on how to configure logging, setting up Serilog, and understanding log levels in Duende products, see our [Logging Fundamentals](/general/logging.md) guide. - -## Configuration - -Logs are typically written under the `Duende.IdentityServer` category. - -We are roughly following the Microsoft guidelines for usage of log levels: - -* **`Trace`** - - For information that is valuable only to a developer troubleshooting an issue. These messages may contain sensitive - application data like tokens and should not be enabled in a production environment. - -* **`Debug`** - - For following the internal flow and understanding why certain decisions are made. Has short-term usefulness during - development and debugging. - -* **`Information`** - - For tracking the general flow of the application. These logs typically have some long-term value. - -* **`Warning`** - - For abnormal or unexpected events in the application flow. These may include errors or other conditions that do not - cause the application to stop, but which may need to be investigated. - -* **`Error`** - - For errors and exceptions that cannot be handled. Examples: failed validation of a protocol request. - -* **`Critical`** - - For failures that require immediate attention. Examples: missing store implementation, invalid key material... - -To get detailed logs from IdentityServer, you can configure your `appsettings.json` to enable `Debug` or `Information` level logs for the `Duende.IdentityServer` namespace: - -```json -// appsettings.json -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Duende.IdentityServer": "Information" - } - } -} -``` - -:::note -In production, logging might produce too much data. It is recommended you either turn it off, or default to the `Warning` level. Have a look at [events](/identityserver/diagnostics/events.md) for more high-level production instrumentation. -::: - -### Filtering Exceptions - -The `LoggingOptions` class allows developers to filter out any exceptions that -could potentially lead to log bloat. For example, in a web application, developers -should expect to see `OperationCanceledException` as clients end HTTP requests -abruptly for many reasons. It's such a common occurrence to see this exception that -the default filter included with IdentityServer excludes it by default. - -```csharp -/// -/// Called when the IdentityServer middleware detects an unhandled exception, and is used to determine if the exception is logged. -/// Returns true to emit the log, false to suppress. -/// -public Func UnhandledExceptionLoggingFilter = (context, exception) => -{ - var result = !(context.RequestAborted.IsCancellationRequested && exception is OperationCanceledException); - return result; -}; -``` - -To apply custom filtering, you can set the `UnhandledExceptionLoggingFilter` property on -the `LoggingOptions` for your `IdentityServerOptions`. - -```csharp -var isBuilder = builder.Services.AddIdentityServer(options => - { - options.Logging.UnhandledExceptionLoggingFilter = - (ctx, ex) => { - if (ctx.User is { Identity.Name: "Jeff" }) - { - // Oh Jeff... - return false; - } - - if (ex.Message.Contains("Oops")) - { - // ignore this exception - return false; - } - - // this is a real exception - return true; - }; - }) - .AddTestUsers(TestUsers.Users) - .AddLicenseSummary(); -``` - -Returning `true` means the exception will be logged, while returning `false` indicates the exception should not be logged. - -## OpenTelemetry - -Logs written to the standard `ILogger` system in .NET 8+ can be exported to OpenTelemetry traces at runtime. This helps visualize when the log statement occurred in relation to the entire request. The logs are augmented with trace ids and correlated with traces. Have a look at [logs in OpenTelemetry](/identityserver/diagnostics/otel.md#logs) for setup details. diff --git a/astro/src/content/docs/identityserver/diagnostics/logging.mdx b/astro/src/content/docs/identityserver/diagnostics/logging.mdx new file mode 100644 index 000000000..6542f9a6c --- /dev/null +++ b/astro/src/content/docs/identityserver/diagnostics/logging.mdx @@ -0,0 +1,96 @@ +--- +title: "Logging" +description: "Documentation for logging configuration and usage in Duende IdentityServer, including log levels and Serilog setup" +date: 2020-09-10T08:22:12+02:00 +sidebar: + order: 10 +redirect_from: + - /identityserver/v5/diagnostics/logging/ + - /identityserver/v6/diagnostics/logging/ + - /identityserver/v7/diagnostics/logging/ +--- + +import { LinkCard } from '@astrojs/starlight/components'; + +Duende IdentityServer uses the standard logging facilities provided by ASP.NET Core. You don't need to do any extra configuration to benefit from rich logging functionality. + +For log level definitions, environment guidance, and actionable next steps for each level, see the [Logging Fundamentals](/general/logging) guide. + + + +## Configuration + +Logs are written under the `Duende.IdentityServer` category. To enable detailed logging for IdentityServer, set that namespace in your `appsettings.json`: + +```json +// appsettings.json +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Duende.IdentityServer": "Debug" + } + } +} +``` + +:::note +In production, logging can produce significant volume. It is recommended to default to `Warning` level and drop to `Information` or `Debug` only when actively investigating an issue. +For high-level production instrumentation, see the [Events](/identityserver/diagnostics/events) system. +::: + +### Filtering Exceptions + +The `LoggingOptions` class allows you to filter out exceptions that could lead to log bloat. For example, `OperationCanceledException` is extremely common in web applications (clients frequently abort HTTP requests) and is excluded by default. + +```csharp +/// +/// Called when the IdentityServer middleware detects an unhandled exception, and is used to determine if the exception is logged. +/// Returns true to emit the log, false to suppress. +/// +public Func UnhandledExceptionLoggingFilter = (context, exception) => +{ + var result = !(context.RequestAborted.IsCancellationRequested && exception is OperationCanceledException); + return result; +}; +``` + +To apply custom filtering, set the `UnhandledExceptionLoggingFilter` property on `LoggingOptions`: + +```csharp +var isBuilder = builder.Services.AddIdentityServer(options => + { + options.Logging.UnhandledExceptionLoggingFilter = + (ctx, ex) => { + if (ctx.User is { Identity.Name: "Jeff" }) + { + // Oh Jeff... + return false; + } + + if (ex.Message.Contains("Oops")) + { + // ignore this exception + return false; + } + + // this is a real exception + return true; + }; + }) + .AddTestUsers(TestUsers.Users) + .AddLicenseSummary(); +``` + +Returning `true` emits the log; returning `false` suppresses it. + + +## Advanced Topics + +### OpenTelemetry + +Logs written to the standard `ILogger` system in .NET 8+ can be exported to OpenTelemetry traces at runtime. This helps visualize when a log statement occurred in relation to the entire request. Logs are augmented with trace IDs and correlated with traces. See [Logs in OpenTelemetry](/identityserver/diagnostics/otel#logs) for setup details. diff --git a/astro/src/content/docs/identityserver/usermanagement/logging.md b/astro/src/content/docs/identityserver/usermanagement/logging.mdx similarity index 83% rename from astro/src/content/docs/identityserver/usermanagement/logging.md rename to astro/src/content/docs/identityserver/usermanagement/logging.mdx index d26359d15..86a847cd0 100644 --- a/astro/src/content/docs/identityserver/usermanagement/logging.md +++ b/astro/src/content/docs/identityserver/usermanagement/logging.mdx @@ -7,11 +7,18 @@ sidebar: order: 10 --- +import { LinkCard } from '@astrojs/starlight/components'; + Duende User Management uses the standard logging facilities provided by ASP.NET Core (`Microsoft.Extensions.Logging`). You don't need any extra configuration to get rich logging out of the box. -For general information on setting up logging, configuring Serilog, and understanding log levels -across all Duende products, see the [Logging Fundamentals](/general/logging.md) guide. +For log level definitions, environment guidance, and actionable next steps for each level, see the [Logging Fundamentals](/general/logging) guide. + + ## Configuration @@ -60,17 +67,10 @@ you can target that sub-category: } ``` -## Log Levels - -User Management follows the standard Microsoft guidelines for log levels: - -* **Information** -- General flow events like authentication attempts starting, succeeding, or failing. Also covers user profile operations, group/role management, and import progress. -* **Warning** -- Unexpected situations that don't stop the application but may need investigation. For example, failing to clean up a consumed passkey challenge, or authentication throttling kicking in. -* **Error** -- Failures that could not be handled gracefully. For example, a passkey registration that failed to persist, or an optimistic concurrency conflict that could not be resolved on retry. - :::note -In production, you typically want to keep logging at `Warning` or higher to avoid excessive log volume. +In production, keep logging at `Warning` or higher to avoid excessive log volume. Drop to `Information` or `Debug` only when actively troubleshooting. +For definitions of each log level and guidance on what to do when you see one, see [Logging Fundamentals](/general/logging). ::: ## What Gets Logged