Programming, error messages and sample code
How to use IdentityServer in ASP.NET Core with certificate signing
Programming, error messages and sample code > ASP.NET
The ASP.NET Core templates offer authentication in Single Page Apps (SPAs) using the support for API authorization. ASP.NET Core Identity for authenticating and storing users is combined with Duende Identity Server for implementing OpenID Connect.
Duende Software might require you to pay a license fee for production use of Duende Identity Server.
Microsoft.AspNetCore.ApiAuthorization.IdentityServer.IdentityServerJwtBearerOptionsConfiguration.ResolveAuthorityAndKeysAsync(MessageReceivedContext messageReceivedContext)
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.AuthenticationHandler<TOptions>.AuthenticateAsync()
Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, string scheme)
Microsoft.AspNetCore.Authentication.AuthenticationHandler<TOptions>.AuthenticateAsync()
Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, string scheme)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) Description: missing definition of the Type of IdentityServer in appsettings.json Error: Unhandled exception. System.InvalidOperationException: Invalid certificate store location ''. Description: the Key:Type of IdentityServer is not File Error: Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'path2') Description: missing certificate file Error: Unhandled exception. System.InvalidOperationException: There was an error loading the certificate. No password was provided. Description: no certificate password was provided Error: Unhandled exception. System.InvalidOperationException: There was an error loading the certificate. Either the password is incorrect or the process does not have permisions to store the key in the Keyset 'DefaultKeySet'
---> System.Security.Cryptography.CryptographicException: The specified network password is not correct. Description: incorrect certificate password Error: Unhandled exception. System.InvalidOperationException: There was an error loading the certificate. Either the password is incorrect or the process does not have permisions to store the key in the Keyset 'DefaultKeySet'
---> System.Security.Cryptography.CryptographicException: The system cannot find the file specified. Description: require "Load user profile" Error: Unhandled exception. System.InvalidOperationException: There was an error loading the certificate. Either the password is incorrect or the process does not have permisions to store the key in the Keyset 'DefaultKeySet'
---> System.Security.Cryptography.CryptographicException: The profile for the user is a temporary profile. Description: require ApplicationPoolIdentity Reference: Authentication and authorization for SPAs
Development
Create an app with API authorization support
Angular:dotnet new angular -au IndividualReact:
dotnet new react -au IndividualBlazor WebAssembly:
dotnet new blazorwasm -ho -au IndividualProgram.cs
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// register database context
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
// Identity with the default UI:
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
// IdentityServer with an additional AddApiAuthorization helper method that sets up some default ASP.NET Core conventions on top of IdentityServer:
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
// Authentication with an additional AddIdentityServerJwt helper method that configures the app to validate JWT tokens produced by IdentityServer:
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();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// 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();
// this is for Blazor WebAssembly
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
// The authentication middleware that is responsible for validating the request credentials and setting the user on the request context:
app.UseAuthentication();
// The IdentityServer middleware that exposes the OpenID Connect endpoints:
app.UseIdentityServer();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");
app.Run();
appsettings.json
In the appsettings.json file of the project root, there's a new IdentityServer section that describes the list of configured clients. In the following example, there's a single client.
"IdentityServer": {
"Clients": {
"{CLIENT PROJECT NAME}": {
"Profile": "IdentityServerSPA"
}
}
}
appsettings.Development.json
In the appsettings.Development.json file of the project root, there's an IdentityServer section that describes the key used to sign tokens. When deploying to production, a key needs to be provisioned and deployed alongside the app, as explained in the Production section.
"IdentityServer": {
"Key": {
"Type": "Development"
}
}
Production
To deploy the app to production, the following resources need to be provisioned:- A database to store the Identity user accounts and the IdentityServer grants.
- A production certificate to use for signing tokens.
- There are no specific requirements for this certificate; it can be a self-signed certificate or a certificate provisioned through a CA authority.
- It can be generated through standard tools like PowerShell or OpenSSL.
- It can be deployed as a .pfx file with a strong password.
"IdentityServer": {
"Clients": {
"{CLIENT PROJECT NAME}": {
"Profile": "IdentityServerSPA"
}
},
"Key": {
"Type": "File",
"FilePath": "H:\\root\\home\\xxx-001\\www\\site1\\certificate.pfx",
"Password": "123456"
}
}
Verify if the IdentiyServer is configured properly
navigate to https://your.domain.com/.well-known/openid-configuration in your browser, you should see the discovery document.
{
"issuer": "https://your.domain.com",
"jwks_uri": "https://your.domain.com/.well-known/openid-configuration/jwks",
"authorization_endpoint": "https://your.domain.com/connect/authorize",
"token_endpoint": "https://your.domain.com/connect/token",
"userinfo_endpoint": "https://your.domain.com/connect/userinfo",
"end_session_endpoint": "https://your.domain.com/connect/endsession",
"check_session_iframe": "https://your.domain.com/connect/checksession",
"revocation_endpoint": "https://your.domain.com/connect/revocation",
"introspection_endpoint": "https://your.domain.com/connect/introspect",
"device_authorization_endpoint": "https://your.domain.com/connect/deviceauthorization",
"backchannel_authentication_endpoint": "https://your.domain.com/connect/ciba",
"frontchannel_logout_supported": true,
"frontchannel_logout_session_supported": true,
"backchannel_logout_supported": true,
"backchannel_logout_session_supported": true,
"scopes_supported": [
"openid",
"profile",
"aAPI",
"offline_access"
],
"claims_supported": [
"sub",
"name",
"family_name",
"given_name",
"middle_name",
"nickname",
"preferred_username",
"profile",
"picture",
"website",
"gender",
"birthdate",
"zoneinfo",
"locale",
"updated_at"
],
"grant_types_supported": [
"authorization_code",
"client_credentials",
"refresh_token",
"implicit",
"password",
"urn:ietf:params:oauth:grant-type:device_code",
"urn:openid:params:grant-type:ciba"
],
"response_types_supported": [
"code",
"token",
"id_token",
"id_token token",
"code id_token",
"code token",
"code id_token token"
],
"response_modes_supported": [
"form_post",
"query",
"fragment"
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"subject_types_supported": [
"public"
],
"code_challenge_methods_supported": [
"plain",
"S256"
],
"request_parameter_supported": true,
"request_object_signing_alg_values_supported": [
"RS256",
"RS384",
"RS512",
"PS256",
"PS384",
"PS512",
"ES256",
"ES384",
"ES512",
"HS256",
"HS384",
"HS512"
],
"authorization_response_iss_parameter_supported": true,
"backchannel_token_delivery_modes_supported": [
"poll"
],
"backchannel_user_code_parameter_supported": true
}
Troubleshoot
Error: NullReferenceException: Object reference not set to an instance of an object.Microsoft.AspNetCore.ApiAuthorization.IdentityServer.IdentityServerJwtBearerOptionsConfiguration.ResolveAuthorityAndKeysAsync(MessageReceivedContext messageReceivedContext)
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.AuthenticationHandler<TOptions>.AuthenticateAsync()
Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, string scheme)
Microsoft.AspNetCore.Authentication.AuthenticationHandler<TOptions>.AuthenticateAsync()
Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, string scheme)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) Description: missing definition of the Type of IdentityServer in appsettings.json Error: Unhandled exception. System.InvalidOperationException: Invalid certificate store location ''. Description: the Key:Type of IdentityServer is not File Error: Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'path2') Description: missing certificate file Error: Unhandled exception. System.InvalidOperationException: There was an error loading the certificate. No password was provided. Description: no certificate password was provided Error: Unhandled exception. System.InvalidOperationException: There was an error loading the certificate. Either the password is incorrect or the process does not have permisions to store the key in the Keyset 'DefaultKeySet'
---> System.Security.Cryptography.CryptographicException: The specified network password is not correct. Description: incorrect certificate password Error: Unhandled exception. System.InvalidOperationException: There was an error loading the certificate. Either the password is incorrect or the process does not have permisions to store the key in the Keyset 'DefaultKeySet'
---> System.Security.Cryptography.CryptographicException: The system cannot find the file specified. Description: require "Load user profile" Error: Unhandled exception. System.InvalidOperationException: There was an error loading the certificate. Either the password is incorrect or the process does not have permisions to store the key in the Keyset 'DefaultKeySet'
---> System.Security.Cryptography.CryptographicException: The profile for the user is a temporary profile. Description: require ApplicationPoolIdentity Reference: Authentication and authorization for SPAs