Identityserver Dcr

作者 DuendeSoftwarefb32edc51982无许可证9 个星标收录于 2026年10月8日更新于 2026年10月8日仓库4周前更新

Configuring Dynamic Client Registration (DCR) in Duende IdentityServer: endpoint setup, authorization policies, custom validation with DynamicClientRegistrationValidator, software statement validation, IClientConfigurationStore, and separate DCR hosting.

AI 生成的概览

指导在 Duende IdentityServer 中配置动态客户端注册,涵盖终结点设置、验证与客户端存储。

功能
说明如何在 Duende IdentityServer 中启用并保护 /connect/dcr 终结点,包括授权策略与 JWT 持有者身份验证。介绍如何通过扩展 DynamicClientRegistrationValidator 自定义验证、验证软件声明,并使用 IClientConfigurationStore 持久化已注册客户端。还涵盖将 DCR 托管在独立应用程序中,并列出反模式与常见陷阱。
适用场景
适用于在 Duende IdentityServer 中按 RFC 7591 设置动态客户端注册,或需要保护、自定义、持久化动态注册客户端时。也适用于将 DCR 与 IdentityServer 主机分开托管的情况。
运行要求
需要 Duende.IdentityServer.Configuration NuGet 包以及 Business Edition 或更高版本的 Duende 许可证;使用 EF 客户端存储时可选 Duende.IdentityServer.Configuration.EntityFramework。仅为说明文档,无脚本;假定存在 ASP.NET Core 主机,独立托管时需要访问 IdentityServer 的网络。

Dynamic Client Registration (DCR)

When to Use This Skill

  • Setting up Dynamic Client Registration (DCR) at /connect/dcr
  • Securing the DCR endpoint with authorization policies
  • Customizing DCR validation with DynamicClientRegistrationValidator
  • Implementing software statement validation
  • Persisting dynamically registered clients with IClientConfigurationStore
  • Hosting DCR in a separate application from IdentityServer

Core Principles

  • DCR requires the Duende.IdentityServer.Configuration NuGet package
  • Requires Business Edition or higher license
  • Always secure the /connect/dcr endpoint with an authorization policy — never expose it unauthenticated
  • Enforce PKCE and restrict allowed grant types in the DCR validator
  • Use persistent stores (database) for dynamically registered clients in production

Docs: https://docs.duendesoftware.com/identityserver/configuration/dcr

Overview

Dynamic Client Registration allows clients to register themselves at the /connect/dcr endpoint per RFC 7591. This feature requires the Business Edition or higher and has been available since version 6.3.

DCR uses a separate NuGet package and can be hosted in the same application as IdentityServer or in a separate host.

Setup

bash
dotnet add package Duende.IdentityServer.Configuration
csharp
// Program.csbuilder.Services.AddIdentityServer()    .AddInMemoryClients(Config.Clients)    .AddInMemoryIdentityResources(Config.IdentityResources)    .AddInMemoryApiScopes(Config.ApiScopes);
builder.Services.AddIdentityServerConfiguration();
var app = builder.Build();
app.UseIdentityServer();app.UseAuthorization();
app.MapDynamicClientRegistration();
app.Run();

MapDynamicClientRegistration() is an endpoint-routing extension from the Duende.IdentityServer.Configuration package (separate from Duende.IdentityServer). Call it where you configure the pipeline/endpoint routing — in the quickstart/template hosts this is the ConfigurePipeline() method (HostingExtensions.cs), alongside UseIdentityServer(). AddIdentityServerConfiguration() registers the DCR services; MapDynamicClientRegistration() maps the /connect/dcr endpoint. Both are required.

Securing the DCR Endpoint

Apply standard ASP.NET Core authorization policies to the DCR endpoint:

csharp
// Using JWT bearer for the DCR endpointbuilder.Services.AddAuthentication()    .AddJwtBearer("dcr", options =>    {        options.Authority = "https://identity.example.com";        options.Audience = "IdentityServer.Configuration";        options.TokenValidationParameters.ValidTypes = ["at+jwt"];    });
builder.Services.AddAuthorization(options =>{    options.AddPolicy("dcr", policy =>    {        policy.AddAuthenticationSchemes("dcr");        policy.RequireAuthenticatedUser();        policy.RequireClaim("scope", "IdentityServer.Configuration");    });});
app.MapDynamicClientRegistration()    .RequireAuthorization("dcr");

DCR Request and Response

Registration request:

POST /connect/dcr HTTP/1.1Content-Type: application/jsonAuthorization: Bearer <access_token>
{    "client_name": "My Dynamic App",    "redirect_uris": ["https://app.example.com/callback"],    "grant_types": ["authorization_code"],    "response_types": ["code"],    "token_endpoint_auth_method": "client_secret_basic"}

Registration response:

json
{  "client_id": "generated-client-id",  "client_secret": "generated-secret",  "client_name": "My Dynamic App",  "redirect_uris": ["https://app.example.com/callback"],  "grant_types": ["authorization_code"],  "response_types": ["code"],  "registration_client_uri": "https://identity.example.com/connect/dcr?client_id=generated-client-id",  "registration_access_token": "..."}

Customizing DCR Validation

Extend DynamicClientRegistrationValidator to add custom validation logic:

csharp
public class CustomDcrValidator : DynamicClientRegistrationValidator{    protected override Task ValidateGrantTypesAsync(        DynamicClientRegistrationContext context)    {        // Only allow authorization_code        var grantTypes = context.Request.GrantTypes;        if (grantTypes.Any(gt => gt != "authorization_code"))        {            context.SetError("Grant type not allowed");            return Task.CompletedTask;        }
        return base.ValidateGrantTypesAsync(context);    }
    protected override Task ValidateRedirectUrisAsync(        DynamicClientRegistrationContext context)    {        // Enforce HTTPS redirect URIs        var uris = context.Request.RedirectUris;        if (uris.Any(u => !u.StartsWith("https://", StringComparison.OrdinalIgnoreCase)))        {            context.SetError("Redirect URIs must use HTTPS");            return Task.CompletedTask;        }
        return base.ValidateRedirectUrisAsync(context);    }
    protected override Task SetClientDefaultsAsync(        DynamicClientRegistrationContext context)    {        // Set defaults for dynamically registered clients        var client = context.Client;        client.RequirePkce = true;        client.AllowOfflineAccess = false;        client.AccessTokenLifetime = 300; // 5 minutes
        return base.SetClientDefaultsAsync(context);    }}

Register:

csharp
builder.Services.AddIdentityServerConfiguration()    .AddDynamicClientRegistrationValidator<CustomDcrValidator>();

DynamicClientRegistrationContext

The context object passed to validation methods contains:

PropertyPurpose
ClientThe IdentityServer Client being built
RequestThe raw DCR request
CallerThe ClaimsPrincipal of the authenticated DCR caller
ItemsDictionary for passing data between validation steps

Software Statements

Software statements are signed JWTs that contain pre-approved client metadata. Validate them by overriding ValidateSoftwareStatementAsync:

csharp
public class SoftwareStatementDcrValidator : DynamicClientRegistrationValidator{    protected override async Task ValidateSoftwareStatementAsync(        DynamicClientRegistrationContext context)    {        var softwareStatement = context.Request.SoftwareStatement;        if (string.IsNullOrEmpty(softwareStatement))        {            context.SetError("Software statement required");            return;        }
        var handler = new JsonWebTokenHandler();        var validationResult = await handler.ValidateTokenAsync(            softwareStatement,            new TokenValidationParameters            {                ValidIssuer = "https://trusted-authority.example.com",                IssuerSigningKeys = await GetTrustedKeysAsync(),                ValidateLifetime = true            });
        if (!validationResult.IsValid)        {            context.SetError("Invalid software statement");            return;        }
        // Apply claims from software statement to the client        var claims = validationResult.ClaimsIdentity;        context.Client.ClientName = claims.FindFirst("software_name")?.Value;
        await base.ValidateSoftwareStatementAsync(context);    }}

Other DCR Extensibility Points

InterfacePurpose
IDynamicClientRegistrationRequestProcessorProcess the DCR request (extend default)
IDynamicClientRegistrationResponseGeneratorCustomize the DCR response

Client Configuration Store

DCR needs a persistent store for dynamically registered clients. Use the Entity Framework implementation:

bash
dotnet add package Duende.IdentityServer.Configuration.EntityFramework
csharp
builder.Services.AddIdentityServerConfiguration()    .AddClientConfigurationStore();

Or implement IClientConfigurationStore for a custom backing store:

csharp
public class CustomClientConfigurationStore : IClientConfigurationStore{    public async Task AddAsync(Client client)    {        // Persist the dynamically registered client    }
    public async Task<Client?> FindByClientIdAsync(string clientId)    {        // Retrieve a dynamically registered client    }
    public async Task UpdateAsync(Client client)    {        // Update client configuration    }
    public async Task DeleteAsync(string clientId)    {        // Remove a dynamically registered client    }}

Separate DCR Host

DCR can be hosted in a separate application from IdentityServer:

csharp
// Separate DCR host — Program.csbuilder.Services.AddIdentityServerConfiguration(options =>{    options.IdentityServerBaseUrl = "https://identity.example.com";});
builder.Services.AddAuthentication()    .AddJwtBearer("dcr", options =>    {        options.Authority = "https://identity.example.com";        options.Audience = "IdentityServer.Configuration";    });
var app = builder.Build();
app.UseAuthentication();app.UseAuthorization();app.MapDynamicClientRegistration().RequireAuthorization("dcr");
app.Run();

Common Anti-Patterns

  • Exposing the DCR endpoint without authentication — Always secure /connect/dcr with an authorization policy.

  • Allowing dynamically registered clients to use any grant type — Restrict allowed grant types and enforce PKCE in the DCR validator.

  • Using in-memory stores for DCR clients in production — Use persistent stores (database) for production deployments.

Common Pitfalls

  1. Business Edition requirement: AddIdentityServerConfiguration() requires a Business Edition or higher license. Community Edition does not support DCR.

  2. Client secrets: Dynamically registered clients receive generated secrets. Ensure your IClientConfigurationStore stores these securely (hashed, not plaintext).

  3. Software statement trust: Software statements must be validated against a trusted signing key. Do not accept software statements signed by unknown issuers.

  4. Separate host connectivity: When hosting DCR separately, it must be able to communicate with IdentityServer's data stores. Ensure the IClientConfigurationStore is backed by the same database that IdentityServer reads from (or uses a shared data layer).

Related Skills

  • identityserver-configuration — IdentityServer host configuration, client types, grant types, secret management, and resource configuration
  • identityserver-saml — SAML 2.0 Identity Provider (the other advanced IdentityServer feature)
  • identityserver-stores — Persistent store patterns (useful for custom IClientConfigurationStore)
  • aspnetcore-authorization — Authorization policies for securing the DCR endpoint
  • identity-security-hardening — Security hardening including HTTPS enforcement

来源与署名

来源:DuendeSoftware/duende-skills位于skills/identityserver-dcr提交fb32edc

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架