0

I have an application that is using identityServer4 for authentication and Angular10(with oidc-client-js) for front-end and an ASP.NET Core API as the resource API. everything was working fine until I added the following line to the API startup configuration , then after log in all my requests were returning 401.

 services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
        .AddIdentityServerAuthentication(options =>
        {
            options.Authority = Configuration.GetSection("ApplicationSettings").GetValue<string>("Authority");
         1-->   options.ApiName = "app-api";
         2-->   options.RequireHttpsMetadata = false;
         3-->   //options.ApiSecret = "apisecret";
        });

and in the IdSrv config I added

  public static IEnumerable<ApiResource> Apis =>
        new ApiResource[]
        {
       4-->     new ApiResource("app-api", "Application Secured API")
            {
                ApiSecrets = { new Secret("apisecret".Sha256()) }
            }
        };

    public static IEnumerable<ApiScope> ApiScopes =>
        new ApiScope[]
    5-->      { new ApiScope("app-api") }; 

  public static IEnumerable<Client> Clients =>
        new Client[]
        {
            new Client {
                ClientName="Test App",
                ClientId="client-spa",
                AllowedGrantTypes = GrantTypes.Code,
                AlwaysIncludeUserClaimsInIdToken = true,
                RedirectUris = new List<string>() { "https://localhost:44383/signin-callback" , "https://localhost:44383/assets/silent-callback.html"}, 
                PostLogoutRedirectUris = {"https://localhost:44383/signout-callback" },
                AllowedCorsOrigins = { "https://localhost:44383" },
                AccessTokenLifetime = 60*5,
                AllowedScopes = {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
             6-->       "app-api"
                },
                RequireClientSecret=false
            }
        };

Client Startup

 public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);

        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "ClientApp/dist/ClientApp";
        });

        services.AddDbContext<MasterDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("PortalMaster")));
        services.AddDbContext<LocalDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("PortalLocal")));
        services.AddDbContext<PropelIdentityContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Identity")));

        services.AddCors(options =>
        {
            options.AddPolicy("AllRequests", builder =>
            {
                builder.AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowAnyOrigin();
            });
        });

        services.AddControllers(options => options.Filters.Add(new PortalHttpResponseExceptionFilter()));
        services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
        // configure Identity Server
        .AddIdentityServerAuthentication(options =>
        {
            options.Authority = "https://localhost:5001/";
            options.ApiName = "app-api";
        });
        
        //Register the Permission policy handlers
        services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();
        services.AddSingleton<IAuthorizationHandler, PermissionHandler>();

    }

  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();

        app.UseStaticFiles();
        if (!env.IsDevelopment())
            app.UseSpaStaticFiles();

        app.UseCors("AllRequests");

        app.UseRouting();

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

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

        app.UseSpa(spa =>
        {
            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                spa.UseAngularCliServer(npmScript: "start");
            }
        });
    }

IdSrv Startup

 public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        //Connection String 
        string connectionString = Configuration.GetConnectionString("Identity");
        services.AddDbContext<AppIdentityContext>(options => options.UseSqlServer(connectionString));


        //AspNetIdentity Configuration 
        services.AddIdentity<AppUser, IdentityRole>(options =>
        {
            options.User.RequireUniqueEmail = false;
            options.Lockout.MaxFailedAccessAttempts = Configuration.GetSection("AppSettings").GetValue<Int32>("MaxFailedAccessAttempts");

            //options.SignIn.RequireConfirmedEmail = true;
            //options.Password.RequiredLength = 8;
            //options.Password.RequireDigit = true;
            //options.Password.RequireUppercase = true;
            //options.Password.RequireLowercase = true;
            //options.Password.RequireNonAlphanumeric = true; 
        })
          .AddUserManager<AppUserManager>()
          .AddEntityFrameworkStores<AppIdentityContext>()
          .AddDefaultTokenProviders();
        //IdentityServer Configuration 
        var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

        var builder = services.AddIdentityServer(options =>
        {
            options.Events.RaiseErrorEvents = true;
            options.Events.RaiseInformationEvents = true;
            options.Events.RaiseFailureEvents = true;
            options.Events.RaiseSuccessEvents = true;
            options.UserInteraction.LoginUrl = "/Account/Login";
            options.UserInteraction.LogoutUrl = "/Account/Logout";
            options.Authentication.CookieLifetime = TimeSpan.FromMinutes(15);
        }).AddAspNetIdentity<PropelUser>()
        .AddProfileService<ProfileService>()
        .AddConfigurationStore(options =>
        {
            options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
        })
        .AddOperationalStore(options =>
        {
            options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
            options.EnableTokenCleanup = true;
        });

        //CORS configuration
        services.AddCors(options =>
        {
            options.AddPolicy("AllowAllOrigins", builder =>
            {
                builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();

            });
        });


        //Signing Credentials. Reading from tempkey saved on project for development, and from SSL certificate on Release
        if (Environment.IsDevelopment())
        {
            builder.AddDeveloperSigningCredential();

        }
        else
        {
            builder.AddSigningCredential(LoadCertificateFromStore());
        }



    }

My question is what is the risk if I remove the ApiResource part(all the marked lines from 1 to 6)? and how can I fix the problem if I should to keep them?

Sarahbe
  • 123
  • 1
  • 16

1 Answers1

0

The best practice is to keep your IdentityServer on a separate service, just so that you can reason about how it all works. When its is one place, its really hard to understand what is going on. I would start with a separate IdentityServer, and then merge when it works and when you fully understand what is going on.

If you get the "You must either set Authority or IntrospectionEndpoint" exception in your API, then the Authority is not properly set. You have the source code for the exception here.

In your Api startup, I would also set the default authentication scheme to:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)

See this page:

Tore Nestenius
  • 16,431
  • 5
  • 30
  • 40
  • no it is still the same, and when I check the logs I have this error ```IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler You must either set Authority or IntrospectionEndpoint System.InvalidOperationException: You must either set Authority or IntrospectionEndpoint``` – Sarahbe Oct 06 '20 at 08:51
  • What does your Startup class look like in your client application? Also, are you sure this config is actually set? options.Authority = Configuration.GetSection("ApplicationSettings") – Tore Nestenius Oct 06 '20 at 09:42
  • I have updated the post up and added the client startup. I am sure that options.Authority is set correctly – Sarahbe Oct 06 '20 at 10:24
  • i rewrote my answer. – Tore Nestenius Oct 06 '20 at 10:39
  • I am sorry I should have added everything from the beginning. I do have a separate project for identityserver and one for the API. I have included my startup for the identityserver. Am I setting the configuration in a wrong way? – Sarahbe Oct 06 '20 at 10:56
  • If you get the error "You must either set Authority or IntrospectionEndpoint System.InvalidOperationException: You must either set Authority or IntrospectionEndpoint" in the API , then I guess your config to set options.Authority = Configuration.GetSection("ApplicationSettings").GetValue("Authority"); is not working? What value do you set options.Authority to? – Tore Nestenius Oct 06 '20 at 11:42
  • options.Authority = "https://localhost:5001/"; The identityServer Url. even when I add the URL as the following instead of getting it from the appsettings, I am still getting the same error – Sarahbe Oct 06 '20 at 12:07
  • the last answer totally solves the issue. Thank you very much for you help. – Sarahbe Oct 07 '20 at 06:11