2

In a project that was started with the template from Visual Studio ASP.NET Core with Angular with the newest version of the template, a new requirement has surfaced to communicate with a Windows Service.

Everything works fine in the web project. The service needs to call an API and POST data so, of course, it needs to login before actually posting the data. This means that it needs to request a token before sending the data.

The problem is that no matter what changes are made to the project or configuration, Postman only receives the answer: "Authentication failed". The configuration of the project was done according the Documentation and according to some other tutorials.

This does not work in new projects also.

Program.cs is:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

builder.Services.AddIdentityServer(options =>
{
    options.Events.RaiseErrorEvents = true;
    options.Events.RaiseInformationEvents = true;
    options.Events.RaiseFailureEvents = true;
    options.Events.RaiseSuccessEvents = true;

    // see https://docs.duendesoftware.com/identityserver/v6/fundamentals/resources/
    options.EmitStaticAudienceClaim = true;
})
    .AddInMemoryIdentityResources(Config.IdentityResources)
    .AddInMemoryApiScopes(Config.ApiScopes)
    .AddInMemoryClients(Config.Clients)
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

builder.Services.AddAuthentication()
    .AddIdentityServerJwt();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action=Index}/{id?}");
app.MapRazorPages();

app.MapFallbackToFile("index.html"); ;

app.Run();

The Config.cs is:

using Duende.IdentityServer.Models;

namespace Project1
{
    public class Config
    {
        public static IEnumerable<IdentityResource> IdentityResources =>
        new IdentityResource[]
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile(),
        };

        public static IEnumerable<ApiScope> ApiScopes =>
            new ApiScope[]
            {
                new ApiScope("scope1"),
                new ApiScope("scope2"),
                new ApiScope("api1"),
            };

        public static IEnumerable<Client> Clients =>
            new Client[]
            {
                // m2m client credentials flow client
                new Client
                {
                    ClientId = "postman",
                    ClientName = "Client Credentials Client",

                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },

                    AllowedScopes = { "api1" }
                },

                // m2m client credentials flow client
                new Client
                {
                    ClientId = "m2m.client",
                    ClientName = "Client Credentials Client",

                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },

                    AllowedScopes = { "scope1" }
                },

                // interactive client using code flow + pkce
                new Client
                {
                    ClientId = "interactive",
                    ClientSecrets = { new Secret("49C1A7E1-0C79-4A89-A3D6-A37998FB86B0".Sha256()) },

                    AllowedGrantTypes = GrantTypes.Code,

                    RedirectUris = { "https://localhost:44300/signin-oidc" },
                    FrontChannelLogoutUri = "https://localhost:44300/signout-oidc",
                    PostLogoutRedirectUris = { "https://localhost:44300/signout-callback-oidc" },

                    AllowOfflineAccess = true,
                    AllowedScopes = { "openid", "profile", "scope2" }
                },
            };
    }
}

The answer in Postman is:

Duende.IdentityServer.Events.DefaultEventService[0]
      {
        "ClientId": "postman",
        "Category": "Authentication",
        "Name": "Client Authentication Failure",
        "EventType": "Failure",
        "Id": 1011,
        "Message": "Unknown client",
        "ActivityId": "0HMK7CLQNRGOT:00000002",
        "TimeStamp": "2022-08-26T13:19:26Z",
        "ProcessId": 30948,
        "LocalIpAddress": "127.0.0.1:7229",
        "RemoteIpAddress": "127.0.0.1"
      }
fail: Duende.IdentityServer.Validation.ClientSecretValidator[0]
      No client with id 'postman' found. aborting

Postman configuration is:

enter image description here

Postman does receive an answer on :

enter image description here

Which clearly shows that "api1" scope is not added. Something devinetly does not work.

No matter what changes are done, it is like the Clients in Config are not loaded because the ones in the database are loaded.

The only difference between our project Program.cs and the documentation (https://docs.duendesoftware.com/identityserver/v5/quickstarts/5_aspnetid/) is that builder.Services.AddIdentityServer() is called there with .AddAspNetIdentity(); but that cannot be changed in an Angular template since the Browser login throws the following error:

System.InvalidOperationException: No service for type 'Duende.IdentityServer.Stores.ISigningCredentialStore' has been registered.

What is the solution to communicate with other types of Clients when Angular project template is used and how can a token can be requested from C#, meaning doing what Postman does?

Andrei Dobrin
  • 1,164
  • 4
  • 19
  • 35
  • Client secret is not the `511536EF-F270-4058-80CA-1C89C192F69A` guid its `Sha256` summary of it. – Eldar Aug 26 '22 at 13:30
  • Thank you @Eldar, but it still does not work. In the tutorials it is not said that the secret should be converted so I assume that Postman does it – Andrei Dobrin Aug 29 '22 at 07:51
  • According to this `No client with id 'postman' found. aborting` error your application is not respecting in-memory client configuration. You can check the `Clients` table if the client `postman` exists. – Eldar Aug 29 '22 at 08:01

0 Answers0