| title | Dynamic Client Registration (DCR) | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| description | Learn how to configure and use Dynamic Client Registration (DCR) to automatically register OAuth clients with IdentityServer | ||||||||||
| sidebar |
|
||||||||||
| redirect_from |
|
import { Code, Steps } from "@astrojs/starlight/components";
export const addMainPackageSnippet = cd Configuration dotnet add package Duende.IdentityServer.Configuration;
export const addStoragePackageSnippet = dotnet add package Duende.IdentityServer.Configuration.EntityFramework;
export const licenseSnippet = builder.Services.AddIdentityServerConfiguration(opt => opt.LicenseKey = "<license>"; );;
export const dbConfigurationSnippet = builder.Services.AddIdentityServerConfiguration(opt => opt.LicenseKey = "<license>" ).AddClientConfigurationStore(); + '\r\n' + var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); builder.Services.AddConfigurationDbContext<ConfigurationDbContext>(options => { options.ConfigureDbContext = builder => builder.UseSqlite(connectionString); });;
export const mapDcrEndpointSnippet = app.MapDynamicClientRegistration() .RequireAuthorization("DCR");;
Dynamic Client Registration (DCR) is the process of registering OAuth clients dynamically. It allows OAuth client applications to programmatically register themselves with an authorization server at runtime, rather than requiring manual configuration.
The client provides information about itself and specifies its desired configuration in an HTTP request to the configuration endpoint. If the request is authorized and valid, the endpoint will then create the necessary client configuration and return an HTTP response describing the new client.
DCR eliminates the need for a manual registration process, making it more efficient and less time-consuming to register new clients. It can help automate the onboarding of new applications in large-scale OAuth ecosystems, such as microservices, mobile apps, and partner APIs.
DCR in Duende IdentityServer is provided as a separate NuGet package,
Duende.IdentityServer.Configuration,
which contains the Configuration API and endpoints required to support DCR.
The Configuration API can be installed in a separate host from IdentityServer, or in the same host. In many cases, it is desirable to host the configuration API and IdentityServer separately. This facilitates the ability to restrict access to the configuration API at the network level separately from IdentityServer and keeps IdentityServer's access to the configuration data read-only. In other cases, you may find that hosting the two systems together better fits your needs.
To host the Configuration API separately from IdentityServer, you will need to create a new ASP.NET Core Web application which will host the Configuration API.
-
Create a new project of type "Empty Web Application"
dotnet new web -n Configuration
-
Add the
Duende.IdentityServer.Configurationpackage -
Configure services to include the Configuration API
:::note This feature is part of the Duende IdentityServer Business and Enterprise Edition. You don't need to acquire an additional license, use the same license key for Duende IdentityServer and the DCR Configuration API. :::
-
Add and configure the client configuration store
The Configuration API uses the
IClientConfigurationStoreabstraction to persist new clients to the configuration store. Your Configuration API host needs an implementation of this interface.You can either use the Entity Framework Core-based implementation, or implement the interface yourself. See the IClientConfigurationStore reference for more details. If you wish to use the built-in implementation, install its NuGet package and add it to the ASP.NET Core service provider.
The
AddClientConfigurationStore()extension method registers the built-in implementation of theIClientConfigurationStoreinterface with the service provider. Make sure to also configure the connection string to the configuration store: -
Map the Configuration API endpoints
The
MapDynamicClientRegistrationextension method registers the DCR endpoints and returns anIEndpointConventionBuilderwhich you can use to define authorization requirements for your DCR endpoint.See Authorization for more details about implementing authorization for the DCR endpoint.
The Configuration API can be hosted by your Duende IdentityServer host.
You'll need to add the Configuration API's services to the service collection,
and configure the store implementation.
-
Add the Duende.IdentityServer.Configuration package
-
Configure services to include the Configuration API
:::note
This feature is part of the Duende IdentityServer Business and Enterprise Edition.
You don't need to acquire an additional license, use the same license key for Duende IdentityServer and the DCR Configuration API.
:::
-
Add and configure the client configuration store
The Configuration API uses the IClientConfigurationStore abstraction to
persist new clients to the configuration store. Your Configuration API host
needs an implementation of this interface.
You can either use the Entity Framework Core-based implementation, or implement
the interface yourself. See the IClientConfigurationStore reference
for more details. If you wish to use the built-in implementation, install its NuGet
package and add it to the ASP.NET Core service provider.
The AddClientConfigurationStore() extension method registers the built-in
implementation of the IClientConfigurationStore interface with the service
provider. Make sure to also configure the connection string to the
configuration store if
you haven't already as part of your IdentityServer host:
-
Map the Configuration API endpoints
The MapDynamicClientRegistration extension method registers the DCR endpoints
and returns an IEndpointConventionBuilder which you can use to define authorization
requirements for your DCR endpoint.
See Authorization for more details about implementing authorization for
the DCR endpoint.
By default, the Dynamic Client Registration (DCR) endpoint is not included in the discovery document of Duende IdentityServer.
To include it, change the Discovery Document options when registering IdentityServer in the service collection:
// Program.cs
builder.Services.AddIdentityServer(options =>
{
// Either use a static URL for the registration endpoint, when hosted outside of IdentityServer:
options.Discovery.DynamicClientRegistration.RegistrationEndpointMode =
RegistrationEndpointMode.Static;
options.Discovery.DynamicClientRegistration.StaticRegistrationEndpoint =
new Uri("https://my-configuration-api/connect/dcr");
// Or use inferred when the registration endpoint is hosted within IdentityServer:
options.Discovery.DynamicClientRegistration.RegistrationEndpointMode =
RegistrationEndpointMode.Inferred;
});
:::note
DCR support was added to Duende IdentityServer v7.4. If you cannot upgrade your IdentityServer solution yet,
you'll have to add custom entries to the Discovery Document instead:
// Program.cs
using Duende.IdentityModel;
builder.Services.AddIdentityServer(options =>
{
options.Discovery.CustomEntries.Add
OidcConstants.Discovery.RegistrationEndpoint,
"https://my-configuration-api/connect/dcr");
});
:::
When implementing Dynamic Client Registration (DCR), it is important to consider
authentication and authorization for the Configuration API endpoint. While not strictly
required, it is recommended that you implement some form of authentication and authorization
for the DCR endpoint. You don't want anyone with access to the DCR endpoint to be able
to register clients!
The specifications that define DCR allow both open registration, where authentication and
authorization are absent and all client software can register with the authorization server,
and protected registration, where an initial access token is required to register.
The Configuration API creates standard ASP.NET endpoints that can be protected
through traditional ASP.NET authorization. Alternatively, the Dynamic Client
Registration software_statement parameter can be used to authenticate requests.
You can authorize access to the Configuration API Endpoints using authorization
policies,
just like any other endpoint created in an ASP.NET Web application. That
authorization policy can use any criteria that an authorization policy might
enforce, such as checking for particular claims or scopes.
One possibility is to authenticate the provisioning system, that is, the system
making the DCR call, using OAuth. The resulting access token could include a
scope that grants access to the Configuration API.
For example, you might protect the Configuration APIs with a JWT-bearer
authentication scheme and an authorization policy that requires a particular
scope to be present in the JWTs. You could choose any name for the scope that
gives access to the Configuration APIs. Let's use the name
IdentityServer.Configuration for this example. You would then define the
IdentityServer.Configuration scope as an ApiScope in your
IdentityServer and allow the appropriate clients to access it.
An automated process running in a CI pipeline could be configured as an OAuth client
that uses the client credentials flow and is allowed to request the IdentityServer.Configuration
scope. It could obtain a token using its client id and secret and then present that token
when it calls the Configuration API. You might also have an interactive web application with a
user interface that makes calls to the Configuration API. Again, you would
define the application as an OAuth client allowed to request the appropriate
scope, but this time, you'd use the authorization code flow.
The metadata within requests to the Configuration API can be bundled together
into a JWT and sent in the software_statement parameter.
If you can establish a trust relationship between the Configuration API and the
issuer of the software statement, then that can be used to decide if you want to
accept registration requests.
To use a software statement in this way, you would need to design the
specific semantics of your software statements. How you will issue them, how you
will create the necessary trust relationship between the issuer and your
Configuration API, and how the Configuration API will validate the software
statements are all aspects to consider.
The configuration API doesn't make any assumptions about the software statement
design. By default, it does nothing with the software_statement parameter.
To make use of software statements, customize the
DynamicClientRegistrationValidator.ValidateSoftwareStatementAsync extension
point and add your validation logic.
The registration endpoint is invoked by making an HTTP POST request to the /connect/dcr endpoint
with a JSON payload containing metadata describing the desired client as described in RFC 7591
and OpenID Connect Dynamic Client Registration 1.0.
The supported metadata properties are listed in the reference section on the DynamicClientRegistrationRequest model.
A mixture of standardized and IdentityServer-specific properties are supported. Most standardized properties that
are applicable to the client credentials or code flow grants are supported.
Where IdentityServer's configuration model includes important properties that are not standardized,
we have included those properties as extensions. For example, there are no standardized properties describing token
lifetimes, so the dynamic client registration endpoint adds absolute_refresh_token_lifetime, access_token_lifetime,
identity_token_lifetime, etc.
The behavior of the Configuration API can be customized through the use of
several extension points that control the steps that occur when a dynamic client
registration request arrives.
First, the incoming request is validated to ensure that it is syntactically
valid and semantically correct. The result of the validation process is a model
which will either contain error details or a validated Client model.
When validation succeeds, the validated request is passed on to the request
processor. The request processor is responsible for generating properties of the
Client that are not specified in the request. For example, the client_id is
not normally specified in the request and is instead generated by the processor.
When the processor is finished generating values, it passes the final client
object to the store and returns an IDynamicClientRegistrationResponse
indicating success or failure. This response object is finally used by the
response generator to generate an HTTP response.
Each of the validation and processing steps might also encounter an error. When
that occurs, errors are conveyed using the DynamicClientRegistrationError
class.
To customize the validation process, you can implement the IDynamicClientRegistrationValidator interface, or
extend the default implementation, DynamicClientRegistrationValidator. The default implementation includes many
virtual methods, allowing you to use most of the base functionality and add your customization in a targeted manner.
Each virtual method is responsible for validating a small number of parameters in the request and setting corresponding
values on the client. A context object is passed to each virtual method. It contains the client object that is being built up,
the original request, the claims principal that made the request, and a dictionary of additional items that can be used to
pass state between customized steps. Each step should update the client in the context and return an IStepResult to
indicate success or failure.
For more details, see the reference section on DCR validation.
The request processor can be customized by implementing the IDynamicClientRegistrationRequestProcessor interface,
or by extending the default DynamicClientRegistrationRequestProcessor. The default request processor contains virtual
methods that allow you to override (part of) its functionality.
For more details, see the reference section on DCR request processing.
To customize the HTTP responses of the Configuration API, you can implement the IDynamicClientRegistrationResponseGenerator
interface, or extend the default DynamicClientRegistrationResponseGenerator.
For more details, see the reference section on DCR response generation.