diff --git a/dotnet/src/Microsoft.Agents.AI.DevUI/DevUIAuthFilter.cs b/dotnet/src/Microsoft.Agents.AI.DevUI/DevUIAuthFilter.cs
new file mode 100644
index 0000000000..b8e4b499f8
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.DevUI/DevUIAuthFilter.cs
@@ -0,0 +1,106 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Net;
+using System.Security.Cryptography;
+using System.Text;
+using Microsoft.Extensions.Options;
+using Microsoft.Net.Http.Headers;
+
+namespace Microsoft.Agents.AI.DevUI;
+
+///
+/// Endpoint filter that enforces the DevUI security posture: loopback-only
+/// access by default, plus optional bearer-token authentication.
+///
+internal sealed class DevUIAuthFilter : IEndpointFilter
+{
+ private const string BearerScheme = "Bearer";
+
+ private readonly DevUIOptions _options;
+ private readonly byte[]? _expectedTokenBytes;
+ private readonly ILogger _logger;
+
+ ///
+ /// Gets a value indicating whether a bearer token is required by this filter
+ /// (either via or the
+ /// DEVUI_AUTH_TOKEN environment variable).
+ ///
+ public bool TokenRequired => this._expectedTokenBytes is { Length: > 0 };
+
+ public DevUIAuthFilter(IOptions options, ILogger logger)
+ {
+ ArgumentNullException.ThrowIfNull(options);
+ ArgumentNullException.ThrowIfNull(logger);
+ this._options = options.Value;
+ this._logger = logger;
+
+ var configuredToken = !string.IsNullOrEmpty(this._options.AuthToken)
+ ? this._options.AuthToken
+ : Environment.GetEnvironmentVariable(DevUIOptions.AuthTokenEnvironmentVariable);
+
+ this._expectedTokenBytes = !string.IsNullOrEmpty(configuredToken)
+ ? Encoding.UTF8.GetBytes(configuredToken)
+ : null;
+ }
+
+ public async ValueTask