Previous Secure API with HTTPS in .NET Core Throttling in .NET core Next

IdentityServer Overview

๐Ÿ” IdentityServer Overview

IdentityServer, now Duende IdentityServer, is an authentication server that implements the OpenID Connect (OIDC) and OAuth 2.0 standards for ASP.NET Core. It acts as a central security token service (STS) for all your applicationsโ€”including web, mobile, and APIsโ€”to provide Single Sign-On (SSO) and API access control in a standardized, secure way.

๐Ÿ“ฆ This approach is highly recommended for complex, modern application architectures (e.g., microservices) where you have multiple client applications (like SPAs and mobile apps) that need to access multiple APIs. For simpler, single-application scenarios, ASP.NET Core Identity may be sufficient.

โš™๏ธ How it works

An IdentityServer instance is a custom ASP.NET Core application that runs the Duende IdentityServer middleware. It exposes several standard endpoints to handle authentication and token issuance.

๐Ÿ“ˆ The high-level flow is:

  • ๐Ÿ‘ค A user accesses a client application (e.g., a web app).
  • ๐Ÿ” The client redirects the user to the IdentityServer's login page for authentication.
  • ๐Ÿ”‘ The user enters their credentials on the IdentityServer's login page, which authenticates the user.
  • ๐ŸŽซ IdentityServer redirects the user back to the client application with an identity token and, potentially, an authorization code.
  • ๐Ÿ“จ The client application uses the code to request an access token from IdentityServer, which it uses to access protected APIs.
  • โœ… The API validates the token and grants or denies access to the requested resource.

๐Ÿงช Example in .NET Core

This example provides the foundational steps to set up an IdentityServer, a client application, and a protected API.

1๏ธโƒฃ Create the IdentityServer project

First, create a new ASP.NET Core project to host IdentityServer.

Install the NuGet package:

dotnet add package Duende.IdentityServer

Add IdentityServer to the service container (Program.cs):

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddIdentityServer()
    .AddInMemoryClients(Config.Clients)
    .AddInMemoryIdentityResources(Config.IdentityResources)
    .AddInMemoryApiScopes(Config.ApiScopes)
    .AddTestUsers(Config.TestUsers) // For development only
    .AddDeveloperSigningCredential(); // For development only

var app = builder.Build();

app.UseIdentityServer(); // Add the middleware
app.Run();
    

Define client and resource configurations (Config.cs):

This example uses in-memory configuration, but in production, you would use a database with Entity Framework Core.

using Duende.IdentityServer.Models;
using Duende.IdentityServer.Test;

public static class Config
{
    public static IEnumerable IdentityResources =>
        new List
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile()
        };

    public static IEnumerable<ApiScope> ApiScopes =>
        new List<ApiScope>
        {
            new ApiScope("api1", "My API")
        };

    public static IEnumerable<Client> Clients =>
        new List<Client>
        {
            new Client
            {
                ClientId = "client",
                AllowedGrantTypes = GrantTypes.ClientCredentials,
                ClientSecrets = { new Secret("secret".Sha256()) },
                AllowedScopes = { "api1" }
            }
        };

    public static List<TestUser> TestUsers =>
        new List<TestUser>
        {
            new TestUser
            {
                SubjectId = "1",
                Username = "alice",
                Password = "password",
                Claims = { new System.Security.Claims.Claim("given_name", "Alice") }
            }
        };
}
    

2๏ธโƒฃ Create the protected API

Next, create a separate API project that trusts and uses IdentityServer.

Install the NuGet package:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

Add authentication services to the API (Program.cs):

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "https://localhost:5001"; // The URL of your IdentityServer
        options.Audience = "api1";
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = false
        };
    });

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();
app.MapControllers().RequireAuthorization();

app.Run();
    

Secure an endpoint:

[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    // ...
}
    

๐Ÿ“Š Advantages and disadvantages

Aspect Advantages Disadvantages
Advantages Centralized security: Provides a single, centralized authentication point, enforcing consistent security policies across all applications.
Single Sign-On (SSO): Users log in once to access multiple applications seamlessly.
Standardized protocols: Based on OpenID Connect and OAuth 2.0, ensuring interoperability with various clients and identity providers.
Extensibility: Highly customizable to fit specific business logic and integrates with ASP.NET Core Identity for user management.
Complexity and learning curve: Implementing and managing IdentityServer is more complex than simple cookie-based authentication and requires a strong understanding of security protocols.
Licensing costs: While older versions were open-source, Duende IdentityServer requires a paid license for most production commercial use cases.
Maintenance overhead: As a self-hosted solution, you are responsible for its security, patching, and scalability.

๐Ÿ’ก Best practices and tips

  • ๐Ÿ” Secure your signing credentials: Use a cryptographically secure certificate for token signing. Never use AddDeveloperSigningCredential() in production. Use a secure secrets store like Azure Key Vault to manage certificates.
  • ๐Ÿ”‘ Use the correct grant type: Always use the Authorization Code with Proof Key for Code Exchange (PKCE) for client-side applications (SPAs, mobile apps). Use Client Credentials for server-to-server communication.
  • ๐Ÿงช Validate tokens correctly: Ensure your APIs are configured to validate tokens by setting the correct Authority and Audience in AddJwtBearer.
  • ๐Ÿ“ฆ Manage clients and scopes correctly: Configure client and resource access appropriately, following the principle of least privilege. Clients should only request the scopes they need.
  • ๐Ÿ—„๏ธ Integrate with a real database: In production, store your configuration (clients, resources) and operational data (tokens, grants) in a persistent store like a database using the Entity Framework Core packages.

๐Ÿ”„ Alternatives to Duende IdentityServer

  • ๐Ÿ†“ OpenIddict: A free, open-source alternative to Duende IdentityServer. It's a library that lets you build your own STS and is a good option if you want to avoid licensing costs but still want full control over your implementation.
  • ๐Ÿงฐ Keycloak: An open-source, Java-based identity and access management (IAM) solution that offers a ready-to-run server and an admin console. It provides more out-of-the-box features than Duende, but may offer less flexibility.
  • โ˜๏ธ Managed services (e.g., Auth0, Microsoft Entra ID): These are cloud-based, identity-as-a-service providers. They reduce your maintenance burden but come with costs and potentially less customization.
Back to Index
Previous Secure API with HTTPS in .NET Core Throttling in .NET core Next
*