< Summary - Kestrun — Combined Coverage

Information
Class: Kestrun.Hosting.KestrunHostAuthExtensions
Assembly: Kestrun
File(s): /home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Hosting/KestrunHostAuthExtensions.cs
Tag: Kestrun/Kestrun@9d3a582b2d63930269564a7591aa77ef297cadeb
Line coverage
78%
Covered lines: 242
Uncovered lines: 66
Coverable lines: 308
Total lines: 734
Line coverage: 78.5%
Branch coverage
75%
Covered branches: 83
Total branches: 110
Branch coverage: 75.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

File(s)

/home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Hosting/KestrunHostAuthExtensions.cs

#LineLine coverage
 1using Microsoft.AspNetCore.Authentication;
 2using Microsoft.AspNetCore.Authentication.Cookies;
 3using Microsoft.AspNetCore.Authentication.JwtBearer;
 4using Microsoft.AspNetCore.Authentication.OpenIdConnect;
 5using Microsoft.IdentityModel.Tokens;
 6using Microsoft.AspNetCore.Authorization;
 7using Microsoft.Extensions.Options;
 8using System.Text.RegularExpressions;
 9using Kestrun.Authentication;
 10using Serilog.Events;
 11using Kestrun.Scripting;
 12using Microsoft.AspNetCore.Authentication.Negotiate;
 13using Kestrun.Claims;
 14using Serilog;
 15
 16
 17namespace Kestrun.Hosting;
 18
 19/// <summary>
 20/// Provides extension methods for adding authentication and authorization schemes to the Kestrun host.
 21/// </summary>
 22public static class KestrunHostAuthExtensions
 23{
 24    /// <summary>
 25    /// Adds Basic Authentication to the Kestrun host.
 26    /// <para>Use this for simple username/password authentication.</para>
 27    /// </summary>
 28    /// <param name="host">The Kestrun host instance.</param>
 29    /// <param name="scheme">The authentication scheme name (e.g. "Basic").</param>
 30    /// <param name="configure">Optional configuration for BasicAuthenticationOptions.</param>
 31    /// <returns>returns the KestrunHost instance.</returns>
 32    public static KestrunHost AddBasicAuthentication(
 33    this KestrunHost host,
 34    string scheme = "Basic",
 35    Action<BasicAuthenticationOptions>? configure = null
 36    )
 37    {
 838        var h = host.AddAuthentication(
 839           defaultScheme: scheme,
 840           buildSchemes: ab =>
 841           {
 842               // ← TOptions == BasicAuthenticationOptions
 843               //    THandler == BasicAuthHandler
 844               _ = ab.AddScheme<BasicAuthenticationOptions, BasicAuthHandler>(
 845                   authenticationScheme: scheme,
 846                   displayName: "Basic Authentication",
 847                    configureOptions: opts =>
 848                   {
 849                       // let caller mutate everything first
 650                       configure?.Invoke(opts);
 651                       ConfigureBasicAuthValidators(opts);
 652                       ConfigureBasicIssueClaims(opts);
 1453                   });
 854           }
 855       );
 56        //  register the post-configurer **after** the scheme so it can
 57        //    read BasicAuthenticationOptions for <scheme>
 858        return h.AddService(services =>
 859        {
 860            _ = services.AddSingleton<IPostConfigureOptions<AuthorizationOptions>>(
 1161                sp => new ClaimPolicyPostConfigurer(
 1162                          scheme,
 1163                          sp.GetRequiredService<
 1164                              IOptionsMonitor<BasicAuthenticationOptions>>()));
 1665        });
 66    }
 67    /// <summary>
 68    /// Adds Basic Authentication to the Kestrun host using the provided options object.
 69    /// </summary>
 70    /// <param name="host">The Kestrun host instance.</param>
 71    /// <param name="scheme">The authentication scheme name (e.g. "Basic").</param>
 72    /// <param name="configure">The BasicAuthenticationOptions object to configure the authentication.</param>
 73    /// <returns>The configured KestrunHost instance.</returns>
 74    public static KestrunHost AddBasicAuthentication(
 75        this KestrunHost host,
 76        string scheme,
 77        BasicAuthenticationOptions configure
 78        )
 79    {
 180        if (host.HostLogger.IsEnabled(LogEventLevel.Debug))
 81        {
 182            host.HostLogger.Debug("Adding Basic Authentication with scheme: {Scheme}", scheme);
 83        }
 84        // Ensure the scheme is not null
 185        ArgumentNullException.ThrowIfNull(host);
 186        ArgumentNullException.ThrowIfNull(scheme);
 187        ArgumentNullException.ThrowIfNull(configure);
 188        return host.AddBasicAuthentication(
 189            scheme: scheme,
 190            configure: opts =>
 191            {
 192                // Copy properties from the provided configure object
 193                opts.HeaderName = configure.HeaderName;
 194                opts.Base64Encoded = configure.Base64Encoded;
 195                if (configure.SeparatorRegex is not null)
 196                {
 197                    opts.SeparatorRegex = new Regex(configure.SeparatorRegex.ToString(), configure.SeparatorRegex.Option
 198                }
 199
 1100                opts.Realm = configure.Realm;
 1101                opts.RequireHttps = configure.RequireHttps;
 1102                opts.SuppressWwwAuthenticate = configure.SuppressWwwAuthenticate;
 1103                // Logger configuration
 1104                opts.Logger = configure.Logger == Log.ForContext<BasicAuthenticationOptions>() ?
 1105                            host.HostLogger.ForContext<BasicAuthenticationOptions>() : configure.Logger;
 1106
 1107                // Copy properties from the provided configure object
 1108                opts.ValidateCodeSettings = configure.ValidateCodeSettings;
 1109                opts.IssueClaimsCodeSettings = configure.IssueClaimsCodeSettings;
 1110
 1111                // Claims policy configuration
 1112                opts.ClaimPolicyConfig = configure.ClaimPolicyConfig;
 1113            }
 1114        );
 115    }
 116
 117
 118    /// <summary>
 119    /// Adds JWT Bearer authentication to the Kestrun host.
 120    /// <para>Use this for APIs that require token-based authentication.</para>
 121    /// </summary>
 122    /// <param name="host">The Kestrun host instance.</param>
 123    /// <param name="scheme">The authentication scheme name (e.g. "Bearer").</param>
 124    /// <param name="validationParameters">Parameters used to validate JWT tokens.</param>
 125    /// <param name="configureJwt">Optional hook to customize JwtBearerOptions.</param>
 126    /// <param name="claimPolicy">Optional authorization policy configuration.</param>
 127    /// <example>
 128    /// HS512 (HMAC-SHA-512, symmetric)
 129    /// </example>
 130    /// <code>
 131    ///     var hmacKey = new SymmetricSecurityKey(
 132    ///         Encoding.UTF8.GetBytes("32-bytes-or-more-secret……"));
 133    ///     host.AddJwtBearerAuthentication(
 134    ///         scheme:          "Bearer",
 135    ///         issuer:          "KestrunApi",
 136    ///         audience:        "KestrunClients",
 137    ///         validationKey:   hmacKey,
 138    ///         validAlgorithms: new[] { SecurityAlgorithms.HmacSha512 });
 139    /// </code>
 140    /// <example>
 141    /// RS256 (RSA-SHA-256, asymmetric)
 142    /// <para>Requires a PEM-encoded private key file.</para>
 143    /// <code>
 144    ///    using var rsa = RSA.Create();
 145    ///     rsa.ImportFromPem(File.ReadAllText("private-key.pem"));
 146    ///     var rsaKey = new RsaSecurityKey(rsa);
 147    ///
 148    ///     host.AddJwtBearerAuthentication(
 149    ///         scheme:          "Rs256",
 150    ///         issuer:          "KestrunApi",
 151    ///         audience:        "KestrunClients",
 152    ///         validationKey:   rsaKey,
 153    ///         validAlgorithms: new[] { SecurityAlgorithms.RsaSha256 });
 154    /// </code>
 155    /// </example>
 156    /// <example>
 157    /// ES256 (ECDSA-SHA-256, asymmetric)
 158    /// <para>Requires a PEM-encoded private key file.</para>
 159    /// <code>
 160    ///     using var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
 161    ///     var esKey = new ECDsaSecurityKey(ecdsa);
 162    ///     host.AddJwtBearerAuthentication(
 163    ///         "Es256", "KestrunApi", "KestrunClients",
 164    ///         esKey, new[] { SecurityAlgorithms.EcdsaSha256 });
 165    /// </code>
 166    /// </example>
 167    /// <returns></returns>
 168    public static KestrunHost AddJwtBearerAuthentication(
 169      this KestrunHost host,
 170      string scheme,
 171      TokenValidationParameters validationParameters,
 172      Action<JwtBearerOptions>? configureJwt = null,
 173      ClaimPolicyConfig? claimPolicy = null)
 174    {
 3175        return host.AddAuthentication(
 3176            defaultScheme: scheme,
 3177            buildSchemes: ab =>
 3178            {
 3179                _ = ab.AddJwtBearer(scheme, opts =>
 3180                {
 0181                    opts.TokenValidationParameters = validationParameters;
 0182                    opts.MapInboundClaims = true;
 0183                    configureJwt?.Invoke(opts);
 3184                });
 3185            },
 3186            configureAuthz: claimPolicy?.ToAuthzDelegate()
 3187            );
 188    }
 189
 190    /// <summary>
 191    /// Adds Cookie Authentication to the Kestrun host.
 192    /// <para>Use this for browser-based authentication using cookies.</para>
 193    /// </summary>
 194    /// <param name="host">The Kestrun host instance.</param>
 195    /// <param name="scheme">The authentication scheme name (default is CookieAuthenticationDefaults.AuthenticationSchem
 196    /// <param name="configure">Optional configuration for CookieAuthenticationOptions.</param>
 197    /// <param name="claimPolicy">Optional authorization policy configuration.</param>
 198    /// <returns>The configured KestrunHost instance.</returns>
 199    public static KestrunHost AddCookieAuthentication(
 200        this KestrunHost host,
 201        string scheme = CookieAuthenticationDefaults.AuthenticationScheme,
 202        Action<CookieAuthenticationOptions>? configure = null,
 203     ClaimPolicyConfig? claimPolicy = null)
 204    {
 2205        return host.AddAuthentication(
 2206            defaultScheme: scheme,
 2207            buildSchemes: ab =>
 2208            {
 2209                _ = ab.AddCookie(
 2210                    authenticationScheme: scheme,
 2211                    configureOptions: opts =>
 2212                    {
 2213                        // let caller mutate everything first
 0214                        configure?.Invoke(opts);
 0215                        Log.Debug("Configured Cookie Authentication with LoginPath: {LoginPath}", opts.LoginPath);
 2216                    });
 2217            },
 2218             configureAuthz: claimPolicy?.ToAuthzDelegate()
 2219        );
 220    }
 221
 222
 223    /// <summary>
 224    /// Adds Cookie Authentication to the Kestrun host using the provided options object.
 225    /// </summary>
 226    /// <param name="host">The Kestrun host instance.</param>
 227    /// <param name="scheme">The authentication scheme name (default is CookieAuthenticationDefaults.AuthenticationSchem
 228    /// <param name="configure">The CookieAuthenticationOptions object to configure the authentication.</param>
 229    /// <param name="claimPolicy">Optional authorization policy configuration.</param>
 230    /// <returns>The configured KestrunHost instance.</returns>
 231    public static KestrunHost AddCookieAuthentication(
 232          this KestrunHost host,
 233          string scheme = CookieAuthenticationDefaults.AuthenticationScheme,
 234          CookieAuthenticationOptions? configure = null,
 235       ClaimPolicyConfig? claimPolicy = null)
 236    {
 237        // If no object provided just delegate to action overload without extra config
 0238        return configure is null
 0239            ? host.AddCookieAuthentication(
 0240                scheme: scheme,
 0241                configure: (Action<CookieAuthenticationOptions>?)null,
 0242                claimPolicy: claimPolicy)
 0243            : host.AddCookieAuthentication(
 0244            scheme: scheme,
 0245            configure: opts =>
 0246            {
 0247                // Copy relevant properties from provided options instance to the framework-created one
 0248                CopyCookieAuthenticationOptions(configure, opts);
 0249            },
 0250            claimPolicy: claimPolicy
 0251        );
 252    }
 253
 254
 255    /*
 256        public static KestrunHost AddClientCertificateAuthentication(
 257            this KestrunHost host,
 258            string scheme = CertificateAuthenticationDefaults.AuthenticationScheme,
 259            Action<CertificateAuthenticationOptions>? configure = null,
 260            Action<AuthorizationOptions>? configureAuthz = null)
 261        {
 262            return host.AddAuthentication(
 263                defaultScheme: scheme,
 264                buildSchemes: ab =>
 265                {
 266                    ab.AddCertificate(
 267                        authenticationScheme: scheme,
 268                        configureOptions: configure ?? (opts => { }));
 269                },
 270                configureAuthz: configureAuthz
 271            );
 272        }
 273    */
 274    /// <summary>
 275    /// Adds Windows Authentication to the Kestrun host.
 276    /// <para>
 277    /// The authentication scheme name is <see cref="NegotiateDefaults.AuthenticationScheme"/>.
 278    /// This enables Kerberos and NTLM authentication.
 279    /// </para>
 280    /// </summary>
 281    /// <param name="host">The Kestrun host instance.</param>
 282    /// <returns>The configured KestrunHost instance.</returns>
 283    public static KestrunHost AddWindowsAuthentication(this KestrunHost host)
 284    {
 1285        return host.AddAuthentication(
 1286            defaultScheme: NegotiateDefaults.AuthenticationScheme,
 1287            buildSchemes: ab =>
 1288            {
 1289                _ = ab.AddNegotiate();
 1290            }
 1291        );
 292    }
 293    /// <summary>
 294    /// Adds API Key Authentication to the Kestrun host.
 295    /// <para>Use this for endpoints that require an API key for access.</para>
 296    /// </summary>
 297    /// <param name="host">The Kestrun host instance.</param>
 298    /// <param name="scheme">The authentication scheme name (default is "ApiKey").</param>
 299    /// <param name="configure">Optional configuration for ApiKeyAuthenticationOptions.</param>
 300    /// <returns>The configured KestrunHost instance.</returns>
 301    public static KestrunHost AddApiKeyAuthentication(
 302    this KestrunHost host,
 303    string scheme = "ApiKey",
 304    Action<ApiKeyAuthenticationOptions>? configure = null)
 305    {
 6306        var h = host.AddAuthentication(
 6307           defaultScheme: scheme,
 6308           buildSchemes: ab =>
 6309           {
 6310               // ← TOptions == ApiKeyAuthenticationOptions
 6311               //    THandler == ApiKeyAuthHandler
 6312               _ = ab.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthHandler>(
 6313                   authenticationScheme: scheme,
 6314                   displayName: "API Key",
 6315                   configureOptions: opts =>
 6316                   {
 6317                       // let caller mutate everything first
 6318                       configure?.Invoke(opts);
 6319                       ConfigureApiKeyValidators(opts);
 6320                       ConfigureApiKeyIssueClaims(opts);
 12321                   });
 6322           }
 6323       );
 324        //  register the post-configurer **after** the scheme so it can
 325        //    read BasicAuthenticationOptions for <scheme>
 6326        return h.AddService(services =>
 6327        {
 6328            _ = services.AddSingleton<IPostConfigureOptions<AuthorizationOptions>>(
 9329                sp => new ClaimPolicyPostConfigurer(
 9330                          scheme,
 9331                          sp.GetRequiredService<
 9332                              IOptionsMonitor<ApiKeyAuthenticationOptions>>()));
 12333        });
 334    }
 335
 336    /// <summary>
 337    /// Configures the validators for Basic authentication.
 338    /// </summary>
 339    /// <param name="opts">The options to configure.</param>
 340    private static void ConfigureBasicAuthValidators(BasicAuthenticationOptions opts)
 341    {
 6342        var settings = opts.ValidateCodeSettings;
 6343        if (string.IsNullOrWhiteSpace(settings.Code))
 344        {
 3345            return;
 346        }
 347
 3348        switch (settings.Language)
 349        {
 350            case ScriptLanguage.PowerShell:
 1351                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 352                {
 1353                    opts.Logger.Debug("Building PowerShell validator for Basic authentication");
 354                }
 355
 1356                opts.ValidateCredentialsAsync = BasicAuthHandler.BuildPsValidator(settings, opts.Logger);
 1357                break;
 358            case ScriptLanguage.CSharp:
 1359                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 360                {
 1361                    opts.Logger.Debug("Building C# validator for Basic authentication");
 362                }
 363
 1364                opts.ValidateCredentialsAsync = BasicAuthHandler.BuildCsValidator(settings, opts.Logger);
 1365                break;
 366            case ScriptLanguage.VBNet:
 1367                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 368                {
 1369                    opts.Logger.Debug("Building VB.NET validator for Basic authentication");
 370                }
 371
 1372                opts.ValidateCredentialsAsync = BasicAuthHandler.BuildVBNetValidator(settings, opts.Logger);
 1373                break;
 374            default:
 0375                if (opts.Logger.IsEnabled(LogEventLevel.Warning))
 376                {
 0377                    opts.Logger.Warning("No valid language specified for Basic authentication");
 378                }
 379                break;
 380        }
 0381    }
 382
 383    /// <summary>
 384    /// Configures the issue claims for Basic authentication.
 385    /// </summary>
 386    /// <param name="opts">The options to configure.</param>
 387    /// <exception cref="NotSupportedException">Thrown when the language is not supported.</exception>
 388    private static void ConfigureBasicIssueClaims(BasicAuthenticationOptions opts)
 389    {
 6390        var settings = opts.IssueClaimsCodeSettings;
 6391        if (string.IsNullOrWhiteSpace(settings.Code))
 392        {
 3393            return;
 394        }
 395
 3396        switch (settings.Language)
 397        {
 398            case ScriptLanguage.PowerShell:
 1399                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 400                {
 1401                    opts.Logger.Debug("Building PowerShell Issue Claims for API Basic authentication");
 402                }
 403
 1404                opts.IssueClaims = IAuthHandler.BuildPsIssueClaims(settings, opts.Logger);
 1405                break;
 406            case ScriptLanguage.CSharp:
 1407                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 408                {
 1409                    opts.Logger.Debug("Building C# Issue Claims for API Basic authentication");
 410                }
 411
 1412                opts.IssueClaims = IAuthHandler.BuildCsIssueClaims(settings, opts.Logger);
 1413                break;
 414            case ScriptLanguage.VBNet:
 1415                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 416                {
 1417                    opts.Logger.Debug("Building VB.NET Issue Claims for API Basic authentication");
 418                }
 419
 1420                opts.IssueClaims = IAuthHandler.BuildVBNetIssueClaims(settings, opts.Logger);
 1421                break;
 422            default:
 0423                if (opts.Logger.IsEnabled(LogEventLevel.Warning))
 424                {
 0425                    opts.Logger.Warning("{language} is not supported for API Basic authentication", settings.Language);
 426                }
 0427                throw new NotSupportedException("Unsupported language");
 428        }
 429    }
 430
 431    /// <summary>
 432    /// Configures the API Key validators.
 433    /// </summary>
 434    /// <param name="opts">The options to configure.</param>
 435    /// <exception cref="NotSupportedException">Thrown when the language is not supported.</exception>
 436    private static void ConfigureApiKeyValidators(ApiKeyAuthenticationOptions opts)
 437    {
 6438        var settings = opts.ValidateCodeSettings;
 6439        if (string.IsNullOrWhiteSpace(settings.Code))
 440        {
 3441            return;
 442        }
 443
 3444        switch (settings.Language)
 445        {
 446            case ScriptLanguage.PowerShell:
 1447                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 448                {
 1449                    opts.Logger.Debug("Building PowerShell validator for API Key authentication");
 450                }
 451
 1452                opts.ValidateKeyAsync = ApiKeyAuthHandler.BuildPsValidator(settings, opts.Logger);
 1453                break;
 454            case ScriptLanguage.CSharp:
 1455                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 456                {
 1457                    opts.Logger.Debug("Building C# validator for API Key authentication");
 458                }
 459
 1460                opts.ValidateKeyAsync = ApiKeyAuthHandler.BuildCsValidator(settings, opts.Logger);
 1461                break;
 462            case ScriptLanguage.VBNet:
 1463                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 464                {
 1465                    opts.Logger.Debug("Building VB.NET validator for API Key authentication");
 466                }
 467
 1468                opts.ValidateKeyAsync = ApiKeyAuthHandler.BuildVBNetValidator(settings, opts.Logger);
 1469                break;
 470            default:
 0471                if (opts.Logger.IsEnabled(LogEventLevel.Warning))
 472                {
 0473                    opts.Logger.Warning("{language} is not supported for API Basic authentication", settings.Language);
 474                }
 0475                throw new NotSupportedException("Unsupported language");
 476        }
 477    }
 478
 479    /// <summary>
 480    /// Configures the API Key issue claims.
 481    /// </summary>
 482    /// <param name="opts">The options to configure.</param>
 483    /// <exception cref="NotSupportedException">Thrown when the language is not supported.</exception>
 484    private static void ConfigureApiKeyIssueClaims(ApiKeyAuthenticationOptions opts)
 485    {
 6486        var settings = opts.IssueClaimsCodeSettings;
 6487        if (string.IsNullOrWhiteSpace(settings.Code))
 488        {
 3489            return;
 490        }
 491
 3492        switch (settings.Language)
 493        {
 494            case ScriptLanguage.PowerShell:
 1495                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 496                {
 1497                    opts.Logger.Debug("Building PowerShell Issue Claims for API Key authentication");
 498                }
 499
 1500                opts.IssueClaims = IAuthHandler.BuildPsIssueClaims(settings, opts.Logger);
 1501                break;
 502            case ScriptLanguage.CSharp:
 1503                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 504                {
 1505                    opts.Logger.Debug("Building C# Issue Claims for API Key authentication");
 506                }
 507
 1508                opts.IssueClaims = IAuthHandler.BuildCsIssueClaims(settings, opts.Logger);
 1509                break;
 510            case ScriptLanguage.VBNet:
 1511                if (opts.Logger.IsEnabled(LogEventLevel.Debug))
 512                {
 1513                    opts.Logger.Debug("Building VB.NET Issue Claims for API Key authentication");
 514                }
 515
 1516                opts.IssueClaims = IAuthHandler.BuildVBNetIssueClaims(settings, opts.Logger);
 1517                break;
 518            default:
 0519                if (opts.Logger.IsEnabled(LogEventLevel.Warning))
 520                {
 0521                    opts.Logger.Warning("{language} is not supported for API Basic authentication", settings.Language);
 522                }
 0523                throw new NotSupportedException("Unsupported language");
 524        }
 525    }
 526
 527
 528    /// <summary>
 529    /// Adds API Key Authentication to the Kestrun host using the provided options object.
 530    /// </summary>
 531    /// <param name="host">The Kestrun host instance.</param>
 532    /// <param name="scheme">The authentication scheme name.</param>
 533    /// <param name="configure">The ApiKeyAuthenticationOptions object to configure the authentication.</param>
 534    /// <returns>The configured KestrunHost instance.</returns>
 535    public static KestrunHost AddApiKeyAuthentication(
 536    this KestrunHost host,
 537    string scheme,
 538    ApiKeyAuthenticationOptions configure)
 539    {
 1540        if (host.HostLogger.IsEnabled(LogEventLevel.Debug))
 541        {
 1542            host.HostLogger.Debug("Adding API Key Authentication with scheme: {Scheme}", scheme);
 543        }
 544
 1545        ArgumentNullException.ThrowIfNull(host);
 1546        ArgumentNullException.ThrowIfNull(scheme);
 1547        ArgumentNullException.ThrowIfNull(configure);
 1548        return host.AddApiKeyAuthentication(
 1549            scheme: scheme,
 1550            configure: opts =>
 1551            {
 1552                // let caller mutate everything first
 1553                opts.ExpectedKey = configure.ExpectedKey;
 1554                opts.HeaderName = configure.HeaderName;
 1555                opts.AdditionalHeaderNames = configure.AdditionalHeaderNames;
 1556                opts.AllowQueryStringFallback = configure.AllowQueryStringFallback;
 1557                // Logger configuration
 1558                opts.Logger = configure.Logger == Log.ForContext<ApiKeyAuthenticationOptions>() ?
 1559                        host.HostLogger.ForContext<ApiKeyAuthenticationOptions>() : configure.Logger;
 1560
 1561                opts.RequireHttps = configure.RequireHttps;
 1562                opts.EmitChallengeHeader = configure.EmitChallengeHeader;
 1563                opts.ChallengeHeaderFormat = configure.ChallengeHeaderFormat;
 1564                opts.ValidateCodeSettings = configure.ValidateCodeSettings;
 1565                // IssueClaimsCodeSettings
 1566                opts.IssueClaimsCodeSettings = configure.IssueClaimsCodeSettings;
 1567                // Claims policy configuration
 1568                opts.ClaimPolicyConfig = configure.ClaimPolicyConfig;
 1569            }
 1570        );
 571    }
 572
 573    /// <summary>
 574    /// Adds OpenID Connect authentication to the Kestrun host.
 575    /// <para>Use this for applications that require OpenID Connect authentication.</para>
 576    /// </summary>
 577    /// <param name="host">The Kestrun host instance.</param>
 578    /// <param name="scheme">The authentication scheme name.</param>
 579    /// <param name="clientId">The client ID for the OpenID Connect application.</param>
 580    /// <param name="clientSecret">The client secret for the OpenID Connect application.</param>
 581    /// <param name="authority">The authority URL for the OpenID Connect provider.</param>
 582    /// <param name="configure">An optional action to configure the OpenID Connect options.</param>
 583    /// <param name="configureAuthz">An optional action to configure the authorization options.</param>
 584    /// <returns>The configured KestrunHost instance.</returns>
 585    public static KestrunHost AddOpenIdConnectAuthentication(
 586        this KestrunHost host,
 587        string scheme,
 588        string clientId,
 589        string clientSecret,
 590        string authority,
 591        Action<OpenIdConnectOptions>? configure = null,
 592        Action<AuthorizationOptions>? configureAuthz = null)
 593    {
 2594        return host.AddAuthentication(
 2595            defaultScheme: scheme,
 2596            buildSchemes: ab =>
 2597            {
 2598                _ = ab.AddOpenIdConnect(
 2599                    authenticationScheme: scheme,
 2600                    displayName: "OIDC",
 2601                    configureOptions: opts =>
 2602                    {
 0603                        opts.ClientId = clientId;
 0604                        opts.ClientSecret = clientSecret;
 0605                        opts.Authority = authority;
 0606                        opts.ResponseType = "code";
 0607                        opts.SaveTokens = true;
 0608                        configure?.Invoke(opts);
 2609                    });
 2610            },
 2611            configureAuthz: configureAuthz
 2612        );
 613    }
 614
 615
 616    /// <summary>
 617    /// Adds authentication and authorization middleware to the Kestrun host.
 618    /// </summary>
 619    /// <param name="host">The Kestrun host instance.</param>
 620    /// <param name="buildSchemes">A delegate to configure authentication schemes.</param>
 621    /// <param name="defaultScheme">The default authentication scheme (default is JwtBearer).</param>
 622    /// <param name="configureAuthz">Optional authorization policy configuration.</param>
 623    /// <returns>The configured KestrunHost instance.</returns>
 624    internal static KestrunHost AddAuthentication(this KestrunHost host,
 625    Action<AuthenticationBuilder> buildSchemes,            // ← unchanged
 626    string defaultScheme = JwtBearerDefaults.AuthenticationScheme,
 627    Action<AuthorizationOptions>? configureAuthz = null)
 628    {
 22629        _ = host.AddService(services =>
 22630        {
 22631            var ab = services.AddAuthentication(defaultScheme);
 22632            buildSchemes(ab);                                  // Basic + JWT here
 22633
 22634            // make sure UseAuthorization() can find its services
 22635            _ = configureAuthz is null ? services.AddAuthorization() : services.AddAuthorization(configureAuthz);
 41636        });
 637
 22638        return host.Use(app =>
 22639        {
 22640            _ = app.UseAuthentication();
 22641            _ = app.UseAuthorization();
 44642        });
 643    }
 644
 645
 646    /// <summary>
 647    /// Adds authorization services to the Kestrun host.
 648    /// </summary>
 649    /// <param name="host">The Kestrun host instance.</param>
 650    /// <param name="cfg">Optional configuration for authorization options.</param>
 651    /// <returns>The configured KestrunHost instance.</returns>
 652    public static KestrunHost AddAuthorization(this KestrunHost host, Action<AuthorizationOptions>? cfg = null)
 653    {
 1654        return host.AddService(s =>
 1655        {
 1656            _ = cfg == null ? s.AddAuthorization() : s.AddAuthorization(cfg);
 2657        });
 658    }
 659
 660    /// <summary>
 661    /// Checks if the specified authentication scheme is registered in the Kestrun host.
 662    /// </summary>
 663    /// <param name="host">The Kestrun host instance.</param>
 664    /// <param name="schemeName">The name of the authentication scheme to check.</param>
 665    /// <returns>True if the scheme is registered; otherwise, false.</returns>
 666    public static bool HasAuthScheme(this KestrunHost host, string schemeName)
 667    {
 15668        var schemeProvider = host.App.Services.GetRequiredService<IAuthenticationSchemeProvider>();
 15669        var scheme = schemeProvider.GetSchemeAsync(schemeName).GetAwaiter().GetResult();
 15670        return scheme != null;
 671    }
 672
 673    // Helper to copy values from a user-supplied CookieAuthenticationOptions instance to the instance
 674    // created by the framework inside AddCookie(). Reassigning the local variable (opts = source) would
 675    // not work because only the local reference changes – the framework keeps the original instance.
 676    private static void CopyCookieAuthenticationOptions(CookieAuthenticationOptions source, CookieAuthenticationOptions 
 677    {
 678        // Paths & return URL
 0679        target.LoginPath = source.LoginPath;
 0680        target.LogoutPath = source.LogoutPath;
 0681        target.AccessDeniedPath = source.AccessDeniedPath;
 0682        target.ReturnUrlParameter = source.ReturnUrlParameter;
 683
 684        // Expiration & sliding behavior
 0685        target.ExpireTimeSpan = source.ExpireTimeSpan;
 0686        target.SlidingExpiration = source.SlidingExpiration;
 687
 688        // Cookie builder settings
 689        // (Cookie is always non-null; copy primitive settings)
 0690        target.Cookie.Name = source.Cookie.Name;
 0691        target.Cookie.Path = source.Cookie.Path;
 0692        target.Cookie.Domain = source.Cookie.Domain;
 0693        target.Cookie.HttpOnly = source.Cookie.HttpOnly;
 0694        target.Cookie.SameSite = source.Cookie.SameSite;
 0695        target.Cookie.SecurePolicy = source.Cookie.SecurePolicy;
 0696        target.Cookie.IsEssential = source.Cookie.IsEssential;
 0697        target.Cookie.MaxAge = source.Cookie.MaxAge;
 698
 699        // Forwarding
 0700        target.ForwardAuthenticate = source.ForwardAuthenticate;
 0701        target.ForwardChallenge = source.ForwardChallenge;
 0702        target.ForwardDefault = source.ForwardDefault;
 0703        target.ForwardDefaultSelector = source.ForwardDefaultSelector;
 0704        target.ForwardForbid = source.ForwardForbid;
 0705        target.ForwardSignIn = source.ForwardSignIn;
 0706        target.ForwardSignOut = source.ForwardSignOut;
 707
 708        // Data protection / ticket / session
 0709        target.TicketDataFormat = source.TicketDataFormat;
 0710        target.DataProtectionProvider = source.DataProtectionProvider;
 0711        target.SessionStore = source.SessionStore;
 712
 713        // Events & issuer
 0714        if (source.Events is not null)
 715        {
 0716            target.Events = source.Events;
 717        }
 0718        target.EventsType = source.EventsType;
 0719        target.ClaimsIssuer = source.ClaimsIssuer;
 0720    }
 721
 722    /// <summary>
 723    /// Checks if the specified authorization policy is registered in the Kestrun host.
 724    /// </summary>
 725    /// <param name="host">The Kestrun host instance.</param>
 726    /// <param name="policyName">The name of the authorization policy to check.</param>
 727    /// <returns>True if the policy is registered; otherwise, false.</returns>
 728    public static bool HasAuthPolicy(this KestrunHost host, string policyName)
 729    {
 14730        var policyProvider = host.App.Services.GetRequiredService<IAuthorizationPolicyProvider>();
 14731        var policy = policyProvider.GetPolicyAsync(policyName).GetAwaiter().GetResult();
 14732        return policy != null;
 733    }
 734}

Methods/Properties

AddBasicAuthentication(Kestrun.Hosting.KestrunHost,System.String,System.Action`1<Kestrun.Authentication.BasicAuthenticationOptions>)
AddBasicAuthentication(Kestrun.Hosting.KestrunHost,System.String,Kestrun.Authentication.BasicAuthenticationOptions)
AddJwtBearerAuthentication(Kestrun.Hosting.KestrunHost,System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters,System.Action`1<Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions>,Kestrun.Claims.ClaimPolicyConfig)
AddCookieAuthentication(Kestrun.Hosting.KestrunHost,System.String,System.Action`1<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>,Kestrun.Claims.ClaimPolicyConfig)
AddCookieAuthentication(Kestrun.Hosting.KestrunHost,System.String,Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions,Kestrun.Claims.ClaimPolicyConfig)
AddWindowsAuthentication(Kestrun.Hosting.KestrunHost)
AddApiKeyAuthentication(Kestrun.Hosting.KestrunHost,System.String,System.Action`1<Kestrun.Authentication.ApiKeyAuthenticationOptions>)
ConfigureBasicAuthValidators(Kestrun.Authentication.BasicAuthenticationOptions)
ConfigureBasicIssueClaims(Kestrun.Authentication.BasicAuthenticationOptions)
ConfigureApiKeyValidators(Kestrun.Authentication.ApiKeyAuthenticationOptions)
ConfigureApiKeyIssueClaims(Kestrun.Authentication.ApiKeyAuthenticationOptions)
AddApiKeyAuthentication(Kestrun.Hosting.KestrunHost,System.String,Kestrun.Authentication.ApiKeyAuthenticationOptions)
AddOpenIdConnectAuthentication(Kestrun.Hosting.KestrunHost,System.String,System.String,System.String,System.String,System.Action`1<Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions>,System.Action`1<Microsoft.AspNetCore.Authorization.AuthorizationOptions>)
AddAuthentication(Kestrun.Hosting.KestrunHost,System.Action`1<Microsoft.AspNetCore.Authentication.AuthenticationBuilder>,System.String,System.Action`1<Microsoft.AspNetCore.Authorization.AuthorizationOptions>)
AddAuthorization(Kestrun.Hosting.KestrunHost,System.Action`1<Microsoft.AspNetCore.Authorization.AuthorizationOptions>)
HasAuthScheme(Kestrun.Hosting.KestrunHost,System.String)
CopyCookieAuthenticationOptions(Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions,Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions)
HasAuthPolicy(Kestrun.Hosting.KestrunHost,System.String)