NTLM over Kestrel 401

Hello, I have a .net7 minimal api running over Kestrel in VS Code. I have negotiate authentication setup for windows auth and it works correctly when hitting any endpoints in the browser or when the app is deployed to IIS.

The problem is that when we try to use postman to hit the endpoints locally we always receive a 401 even with NTLM auth setup with the correct credentials. It doesnt even seem like it hits our middleware. I have SSL disabled in postman and no certificates set.

"https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": false,
      "applicationUrl": "https://localhost:7297;http://localhost:5209",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "windowsAuthentication": true,
      "anonymousAuthentication": false
    },
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
    .AddNegotiate();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = options.DefaultPolicy;
});
app.UseAuthentication();
app.UseAuthorization();

Here is the console log in postman:

GET https://localhost:7297/GetStatusOptions4015 ms

Warning: Unable to verify the first certificate

  • :play_button:Network
  1. :play_button:addresses: {…}

  2. :play_button:local: {…}

1. address: "::1"

2. family: "IPv6"

3. port: 63028
  1. :play_button:remote: {…}
1. address: "::1"

2. family: "IPv6"

3. port: 7297
  1. :play_button:tls: {…}

  2. reused: false

  3. authorized: false

  4. authorizationError: “UNABLE_TO_VERIFY_LEAF_SIGNATURE”

  5. :play_button:cipher: {…}

1. name: "ECDHE-RSA-AES256-GCM-SHA384"

2. standardName: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"

3. version: "TLSv1/SSLv3"
  1. protocol: “TLSv1.2”

  2. ephemeralKeyInfo: {}

  3. :play_button:peerCertificate: {…}

1. ▶subject: {…}

  1. commonName: "localhost"

  2. alternativeNames: "DNS:localhost"
2. ▶issuer: {…}

  1. commonName: "localhost"
3. validFrom: "Dec 4 17:08:56 2024 GMT"

4. validTo: "Dec 4 17:08:56 2025 GMT"

5. fingerprint: "D2:E6:51:B1:70:A5:8C:CD:B8:E4:0A:60:CB:42:BD:CD:F6:99:C0:6C"

6. serialNumber: "8e8de005f9957524"

:play_button:Request Headers

User-Agent: PostmanRuntime/7.43.2

Accept: /

Cache-Control: no-cache

Postman-Token: 9ba8828a-84c7-40a1-940c-327102498669

Host: localhost:7297

Accept-Encoding: gzip, deflate, br

Connection: keep-alive

:play_button:Response Headers

Content-Length: 0

Date: Wed, 19 Mar 2025 14:37:24 GMT

Server: Kestrel

WWW-Authenticate: Negotiate

:play_button:Response Body

2 Likes

Hey Tyler, welcome to the Postman Community!

Thanks for sharing your question. While I don’t have a solution for you just yet, I wanted to acknowledge your issue and let you know that help is on the way soon. Our community is full of knowledgeable folks, so I’m sure someone will chime in with insights.

Appreciate you being here, and thanks for kicking off the conversation!

1 Like

Hey @trayford70. Welcome to the Postman Community :postman_logo:.

You will need to provide some more information to enable us understand the problem you’re experiencing better.

The console output you shared looks like a console output from your server. is this correct? A 401 status code is an authorization status code. Can you share how you’re managing your authorization in Postman? Postman has an NLTM authorization helper, are you using that to setup your authorization?

Hello @gbadebo-bello!

That console output is from the Postman desktop client v11.37.1. I have NTLM authorization setup with my AD username and password. I have tried with and without specifying the domain and I have SSL turned off in the settings globally and in the request settings. My .NET API is running over Kestrel and I posted my auth code setup in the original post.

Based off the postman console, it seems that it is receiving the Negotiate response but it never responds the second time. I will try to upload as much info as I can in this post. Let me know if I have missed anything!



@trayford70
Good Morning All,
I may see that your baseUrl is your localhost. Whether you can share your collection that will be helpful to check that unit test. The issue could be on your end. There is no information regarding your rooting or your method actions.

Thank you for sharing.

@jecorde

Hello, I also think it may be something on our end but I cannot figure out what it is. I’m not too familiar with how certificates work but my guess is its something to do with that. All I’ve done in my dev vm is generate a cert like so:

dotnet dev-certs https --trust

Unfortunately, I dont think I can share the collection for company reasons but yes the baseURL value is https://localhost:7297, which is correct.

As for the routing and method actions, is this what you are looking for? Ive stripped out what I dont think i can share but here is the setup for the API. Please let me know what other info I need to supply!

using Microsoft.AspNetCore.Server.Kestrel.Https;

var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;


builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowSpecificOrigin",
        builder =>
        {
            builder.WithOrigins(origins)
                .AllowAnyHeader()
                .AllowAnyMethod()
                .AllowCredentials();
        });
});

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
    .AddNegotiate();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = options.DefaultPolicy;
});


var app = builder.Build();


app.UseHttpsRedirection();
app.UseCors("AllowSpecificOrigin");
app.UseAuthentication();
app.UseAuthorization();

app.MapGet("/GetStatusOptions", [Authorize] async (Context db, string stripped) =>
{
 //STRIPPED EF LINQ QUERY
});

app.Run();
1 Like