When every unauthorized request becomes the same dashboard line, diagnosis turns into guessing.
ASP.NET Core 10 authentication metrics give me a better split: did the handler have nothing to authenticate, reject supplied credentials, or accept them?
That distinction matters because a client deployment that drops credentials needs a different response from a surge of malformed or expired credentials.
ASP.NET Core 10 added built-in authentication and authorization instruments to .
I can collect them without rewriting each handler, and I can lock their behavior into an offline test before wiring up a production exporter.
Why one 401 hides two different problems A protected endpoint normally challenges an unauthenticated caller.
The final status is 401 whether the caller sent nothing or the handler rejected what it received.
The authentication duration histogram exposes the missing context through : Result What the handler reported A common interpretation No authentication result No applicable credentials were available Authentication failed Supplied credentials were rejected or processing failed A principal was created Authentication completed successfully Another framework result Preserve it as an explicit catch-all is a handler result, not a universal synonym for “missing Authorization header.” A policy scheme or custom handler can make a different choice.
I verify the behavior of the schemes I actually deploy instead of building an alert from the label alone.
Likewise, means the handler produced an authentication ticket.
Authorization can still deny that principal, so it does not promise a 2xx response.
The separate counter answers another question: how often was a scheme challenged?
Both a result and a result can be followed by a challenge, so challenge count cannot replace the result split.
A challenge is an authentication operation, not an HTTP-status counter; a cookie handler can redirect instead of returning
401.
ASP.NET Core 10 authentication metrics to collect The ASP.NET Core 10 release notes list the new authentication and authorization coverage.
The detailed built-in security metrics reference defines the instruments and attributes.
For this incident pattern, I start with the meter: is a histogram in seconds with conditional result and scheme attributes. counts challenges by scheme. counts authenticated callers denied access. and cover explicit sign-in and sign-out operations.
The framework may also attach when authentication fails or an operation ends with an error.
That is intentionally an exception type, not an exception message.
I keep it that way: token text, user IDs, email addresses, and arbitrary error messages do not belong in metric attributes.
With OpenTelemetry, the key configuration is to include the meter in the metrics pipeline: An exporter and backend are still required for production storage.
The built-in instrumentation only creates measurements.
Lock the result split into a test I prefer a small regression harness over discovering the metric shape after a dashboard ships.
The complete sample uses , a fake authentication handler, and ; it opens no network socket and needs no identity provider.
It sends three requests: In this deliberately single-scheme app, the fake handler maps the absent header to and the rejected value to .
Authorization separately challenges both unauthenticated requests, so both return
401.
The accepted credential produces and returns
200.
The verifier checks the exact result set, the fixed scheme, two challenges, for the failed result, the documented attribute-name allowlist, and that neither credential nor the exception message appears in an attribute value.
I do not assert duration values.
A histogram measurement depends on the machine and runtime conditions; the contract I care about here is the instrument name and bounded attributes.
Microsoft's metrics testing guidance follows the same principle of collecting measurements around an action and asserting the useful result.