Dynamic Client Registration Authentication Methods

Dynamic Client Registration Authentication Methods

On this page

Getting started with DCR

The Dynamic Client Registration (DCR) Overview article provides an overview of the RFC7591 standard and provides a summary of the two OAuth clients involved in a DCR flow:

ClientUsage
DCR Initial ClientAn initial client used to send a Registration Request, to create an application client
Application ClientCreated by the dynamic client registration request, to return a generated client_id, along with a client_secret in some cases

For a getting started guide on DCR, see the Using Dynamic Client Registration article, which provides example registration request and response messages.

Main DCR Use Cases

Dynamic client registration needs to be secured in order to prevent a malicious party gaining access, and how this is done will depend upon your use case. This article will therefore describe the DCR building blocks and some common approaches.

Mobile High Security

One of the main use cases for DCR is to strengthen mobile security, so that each installed instance of the mobile app has a unique client_id and client_secret that is then used to protect requests for OAuth tokens, as described in Mobile Best Practices. In some setups this fits neatly with Mobile Device Management (MDM) systems used to prepare devices given to company employees. MDM systems can provision each device with a user specific secret, such as a client certificate and key, that is then also used for DCR authentication.

APIs with Dynamic Clients

The second main use case for DCR is when a company wants to provide API access for business partners in a dynamic manner. The Open Banking initiative is a great example of this use case, which encourages business innovation. Banks must expose APIs according to regulations, enabling an ecosystem where Third Party Providers (TPP), such as online retailers, can securely onboard with no delays, to enable their users to make online purchases via their bank accounts.

Portals and Management Systems

Another common DCR use case is when creating online accounts with a technology provider. A credential is often provided after registering, then used to create OAuth clients for applications. This type of solution sometimes only provides fairly basic security, targeted at developers.

Securing DCR

The main authentication techniques are summarized below, providing a toolbox for managing dynamic client registration and adapting it to your needs. These tools can be applied in multiple ways, and we will drill into common solutions in this article.

Authentication TechniqueBehavior Summary
User AuthenticatesAn end user supplies credentials in order to get an initial access token used to perform the DCR registration
Client AuthenticatesA client application supplies credentials in order to get an initial access token used to perform the DCR registration
Mutual TLSThe DCR registration is performed over a Mutual TLS channel, to securely identify a trusted client
Software StatementThe client includes a JWT in the registration request with further information that is verified before registration is allowed
Custom Pre-ProcessingThe Identity Server enables custom logic to be applied during a DCR registration request

User Authentication Methods

DCR user authentication is used primarily in mobile use cases, when you want to strengthen mobile OAuth security but cannot control the devices via MDM, e.g. for an app deployed to internet users. In this case the user's credentials can be used for both DCR authentication and also the app's main OAuth flow. The app can then use mobile secure storage to save the secret, then use it later, in requests for tokens. This results in the following overall flow:

User Authenticates Flow

In the Curity Identity Server, the user authenticates behavior is configured by enabling the Authenticate User By option, then configuring the initial DCR client:

User Authenticates

Code Flow

It is possible to use various UI flows to sign the user in, such as the Implicit Flow, though these days you would most commonly use Authorization Code Flow with PKCE instead, and an example implementation is provided in the Mobile DCR tutorial. The app first performs an OpenID Connect redirect with the dcr scope, then the user enters their credentials:

GET https://login.example.com/oauth/v2/oauth-authorize
?client_id=mobile-dcr-initial-client
&redirect_uri=https://mobile.example.com
&response_type=code
&code_challenge=l9QIPE4TFgW2y7STZDSWQ4Y4CQpO8W6VtELopzYHdNg
&code_challenge_method=S256
&state=NlAoISfdL1DxPdNGFBljlVuB1GDjgGARmqDcxtHhV8iKNYu6ECS2KOavDHpI3eLN
&scope=dcr

The returned authorization code is then swapped for a DCR access token using a standard authorization code grant message:

POST https://login.example.com/oauth/v2/oauth-token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
client_id=mobile-dcr-initial-client&
redirect_uri=https://mobile.example.com&
code=YFFX2HmFNnrMS8alWIZH83oim9ZHgwRh&
code_verifier=ItJtBXUGtHs-3FpUHB8qW9uJ00XcwTfeiZdLGquawMg

The mobile app then sends the DCR access token in a registration request to the Identity Server's DCR endpoint. The details sent indicate the flow the created client will use later, and in this example the code flow is specified, since that is the standard option for mobile apps:

POST https://login.example.com/token-service/oauth-registration
Authorization: Bearer e99ab41e-52a1-4fa3-b21b-fb95a398c33a
Content-Type: application/json

{
    "redirect_uris":["io.curity.dcrclient:/callback"],
    "post_logout_redirect_uris":["io.curity.dcrclient:/logoutcallback"],
    "application_type":"native",
    "grant_types":["authorization_code"],
    "scope":"openid profile"
}

The response to the client will then include the dynamically added client_id and client_secret, which the app will then use from that point forwards:

{
	"client_id": "87f1d9de-de2f-4e96-b27b-882cce0a3352",
	"client_secret": "tfs9nad3dweFAa1CqpUj5p6NC4-092hb5Gg4SVRhOkc",
}

After this one-time registration, the user will be redirected again, to perform the newly created client's OAuth flow, and this will be a Single Sign On event, since the initial login will have resulted in the Identity Server issuing a session cookie. On all subsequent logins from this point forwards, there is only a single user redirect.

Delivery of a DCR Access Token

Alternative options can be used to deliver the initial access token with the dcr scope to the user's device, via an out-of-band mechanism. A common option is for a back end service to perform client authentication to get the DCR access token, then deliver that to the mobile device, e.g. via a mobile push notification.

Client Authentication Methods

When client authentication is configured, an initial client is created which must be used in order to get a DCR access token, via the Client Credentials flow. The general flow is illustrated below, and multiple forms of client credential can be used, which will be summarized in the following sections.

Client Authenticates Flow

In the Curity Identity Server this behavior is configured by enabling the Authenticate Client By option, then configuring the initial DCR client:

Client Authenticates

Trust

Before a client authenticates, there needs to be some form of trust configured, to prevent a malicious party from gaining access. The following two main options are used to manage trusted clients:

Trust MechanismUsage
Central AuthorityClients have to be approved by an industry specific authority and are then issued with a digital client credential, which the service provider can trust, without the need for any manual steps.
Out of BandThe service provider uses an out of band mechanism to approve future clients as a prerequisite. This might involve a people process to configure trusted digital credentials, to enable dynamic registration at a later time.

Trust between companies most commonly is based on Public Key Infrastructure (PKI), in which case either client certificates or asymmetric keys are used to secure the DCR process.

Discovering Authentication Methods

To dynamically register, a client can start by downloading the Provider Metadata from the OpenID Connect Discovery Endpoint. The client authentication methods that are active are returned in the following response fields:

Metadata FieldUsage
token_endpoint_auth_methods_supportedIndicates the forms of client authentication that can be used, which may include Mutual TLS and JWT client assertions
token_endpoint_auth_signing_alg_values_supportedIndicates token signing algorithms that will be accepted when a JWT client assertion is supplied as a client secret

The possible authentication methods are briefly summarized below, and the most secure options are private_key_jwt and tls_client_auth. Using symmetrically signed JWTs is not usually a secure option for DCR so it will not be discussed further in this article.

Token Endpoint Authentication MethodBehavior
client_secret_basicA string client secret sent in the HTTP Authorization Header as a basic credential
client_secret_postA string client secret sent as a form post
client_secret_jwtA JWT that is symmetrically signed and uses a signing key known by both the client and the Identity Server
private_key_jwtA JWT that is asymmetrically signed, with the private key only known by the client
extended optionsCustom values can also be returned, and the Curity Identity Server adds tls_client_auth when Mutual TLS is enabled

String Client Secret

In some setups it is possible to use a simple string client_secret to get the initial DCR access token. This is the most basic form of the client credentials flow and does not provide strongest security. The client credential is sent via either client_secret_basic or client_secret_post and this example request uses the POST option:

POST https://login.example.local:8443/oauth/v2/oauth-token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&
client_id=dcr-initial-client&
client_secret=my-secret&
scope=dcr

In the Curity Identity Server this would require the initial DCR client to be configured with the same client_id and client_secret as the caller, so that the server can validate credentials when DCR requests are received:

DCR String Secret

This type of option might be used in an portal system, where the user is given the credential after registering. It might also be used in scenarios where the client credentials can be exchanged securely in advance, via an out-of-band mechanism.

Client Certificate Secret

A higher security option is to send a client credential that proves proof of ownership of a client certificate and key. This might be used in a B2B API use case, or with MDM when there is a client certificate installed on the device. A Mutual TLS channel is then used to get the DCR access token, as in this example curl request:

curl -X POST "https://login.example.com/oauth/v2/oauth-token-mutual-tls" \
--cert "example.clientcert.p12":"mycert-privatekeypassword" \
--cert-type P12 \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=dcr-initial-client" \
-d "scope=dcr"

In this setup the DCR initial client is commonly configured to only allow client certificates from an approved issuer, such as a business partner or MDM system. Various PKI options can be used to verify the client certificate, and the configuration should allow the client certificate to be renewed without breaking changes.

DCR Certificate Secret

The infrastructure involved in managing Mutual TLS and transport level security can be tricky to manage if you are not familiar with it, and typically requires dedicated ports or endpoints. For an end-to-end worked example, see the Mutual TLS API tutorial.

JWT Client Assertions

A high security option that may be easier to manage is to use PKI via message level security and asymmetric keys. This involves installing a JSON Web Key in the client, then writing code to create and send a JWT Assertion as the client credential. An example request to authenticate and get a DCR access token is shown here, and note that the client_id field is sent as a claim in the JWT assertion:

POST https://login.example.local:8443/oauth/v2/oauth-token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
client_assertion=eyJraWQiOiIxNjE5Nzc1NDQ...&
scope=dcr

The DCR initial client would then be configured to only accept trusted JWT assertions. Although this can be done by specifying the asymmetric public key value, it is more usual to configure the trusted JWKS URI of the client, since this enables keys to be rotated.

DCR Certificate Secret

Registration

Once a client has completed DCR authentication and has a valid DCR access token, the registration request will be sent. The fields sent are explained in the Client Metadata section of the DCR specification. A key behavior of the DCR request is to express how the application client created will authenticate later. This is managed by sending the following values:

Registration FieldUsage
grant_typesThis will be authorization_code when registering a mobile client, or client_credentials when registering an API client
token_endpoint_auth_methodOne of the token_endpoint_auth_methods_supported values discussed earlier
jwks_uriA URL that will later be used to get token signing public keys for validating client assertions, for clients that use the private_key_jwt method
jwksA token signing public key passed by value and used later to validate client assertions, for clients that use the private_key_jwt method

For clients that authenticate via JWT assertions, it is most standard to supply the jwks_uri field. The jwks field is for clients that cannot provide a URL, and might be used by a standalone mobile app, but this has the disadvantage that the key cannot easily be rotated, so this is rarely used in practice.

Financial-grade DCR Authentication

This section summarizes some advanced DCR patterns used in Open Banking, where a trusted authority provides client credentials along with additional details about the client identity, and the server must implement some extended validation during DCR requests.

Mutual TLS

Instead of using an initial client and a DCR access token, it is possible to authenticate during the main DCR registration request, using a Mutual TLS tunnel and a trusted client certificate. In this case there is no need for an initial access token with the dcr scope, or a DCR initial client. This option is commonly used in financial-grade scenarios, where the application client will then also use Mutual TLS and Certificate Bound Access Tokens to call APIs.

The end-to-end flow might then look like this, where the client uses a Mutual TLS tunnel for all requests. It is possible to use a Mutual TLS tunnel all the way through to back end components, or Mutual TLS can be terminated and verified at the reverse proxy, which is commonly done for API requests:

Mutual TLS Flow

In the Curity Identity Server this results in the following configuration, where one or more trusted issuers are specified. In Open Banking, only client certificates issued by the trusted central authority are allowed, e.g. by eIDAS in Europe. Therefore the authority's root and intermediate certificates would be configured as trusted issuers, meaning that client certificates from any other issuer would be rejected:

Mutual TLS Authentication

Software Statements

When a central authority approves a client for Open Banking, a credential is issued, most commonly in the form of a client certificate and key. In addition the authority can also provide claims, such as business roles assigned to the client, so that the service provider receives useful context.

The client downloads this information from the authority at runtime, as a JWT signed assertion, then sends it in the registration request in the software_statement field. The registration request will then include both the assertion and details on how the final client will authenticate later:

{
  "token_endpoint_auth_method": "tls_client_auth",
  "tls_client_auth_subject_dn": "CN=tpp.example.com,OU=368a900d-89a3-4c59-a624-1387f1b541fb,O=Testing Bank,L=Sao Paulo,ST=SP,C=BR",
  "software_statement": "eyJraWQiOiItMTY1ODk3MjgyNSIsIng1dCI6 ..."
}

Validating the software statement is domain specific work that must be done in custom code, similar to how an API validates claims. This requires a setup where DCR pre-processing can be run before forwarding the registration request to the Identity Server.

DCR Pre-Processing

In some industry sectors, authorities publish regulations on how incoming DCR requests must be validated, and the logic may differ depending on the country or region. This will require standards based security verification from the Identity Server, and also enforcement of business rules associated with the software statement.

Typically the service provider will need to implement a solution using the extensibility features of the Identity Server or by coding it in a reverse proxy, before the request is routed to the Identity Server. The following resources provide further details on an advanced use case:

Although these links are focused on a particular industry sector and region, the techniques used are general security design patterns for enabling dynamic business, and could be applied to other use cases. The ability to receive custom data via claims, then verify them both digitally and in business terms, enables secure immediate onboarding.

Dynamic Client Management

This article has focused primarily on the DCR behavior from the RFC7591 standard, and the result will be that details for each unique client are stored in a database table, which in the Curity Identity Server is named dynamically_registered_clients. Each database row will contain the information from the DCR response message, and for a mobile client this may include data similar to this:

{
	"default_acr_values": ["urn:se:curity:authentication:html-form:Username-Password"],
	"application_type": "native",
	"registration_client_uri": "https://baa467f55bc7.eu.ngrok.io/token-service/oauth-registration/87f1d9de-de2f-4e96-b27b-882cce0a3352",
	"registration_access_token_expires_in": 31536000,
	"registration_access_token": "e99ab41e-52a1-4fa3-b21b-fb95a398c33a",
	"client_id": "87f1d9de-de2f-4e96-b27b-882cce0a3352",
	"token_endpoint_auth_method": "client_secret_basic",
	"scope": "openid profile",
	"client_id_issued_at": 1624011134,
	"client_secret": "tfs9nad3dweFAa1CqpUj5p6NC4-092hb5Gg4SVRhOkc",
	"id_token_signed_response_alg": "RS256",
	"grant_types": ["authorization_code", "refresh_token"],
	"subject_type": "public",
	"redirect_uris": ["io.curity.dcrclient:/callback"],
    "post_logout_redirect_uris":["io.curity.dcrclient:/logoutcallback"],
	"client_secret_expires_at": 0,
	"token_endpoint_auth_methods": ["client_secret_basic", "client_secret_post"],
	"response_types": ["code", "id_token"],
	"refresh_token_ttl": 3600
}

The client's DCR data may then need to be updated in future, which is managed by including a Registration Access Token in the response, which the client app must save. To make updates the client uses Dynamic Client Registration Management, as defined in RFC7592, and sends this token.

Template Clients

For mobile clients, using a separate dynamic client per device can result in a lot of duplicated settings, so an extended option called Templatized DCR is also provided in the Curity Identity Server. This enables values such as redirect_uri and scope to be managed centrally, so that any configuration changes immediately come into effect for all dynamic clients that used the template to register.

DCR Template Client

When using template clients, one of the Client Authenticates or User Authenticates options must be used, and the client must always use a DCR access token to register. The initial client authentication can continue to be done using client certificates or client assertions. During registration the template client is referenced via the software_id field, which is used to group related DCR clients:

POST https://login.example.com/token-service/oauth-registration
Authorization: Bearer e99ab41e-52a1-4fa3-b21b-fb95a398c33a
Content-Type: application/json

{
    "software_id": "dcr-template-client"
}

The registration response is then the same as previously, and each mobile instance receives a different client_id and client_secret. The app will save the secret to the device's built-in secure storage, then use it to strengthen token requests to the Identity Server.

{
	"client_id": "87f1d9de-de2f-4e96-b27b-882cce0a3352",
	"client_secret": "tfs9nad3dweFAa1CqpUj5p6NC4-092hb5Gg4SVRhOkc",
}

Conclusion

The two main use cases for Dynamic Client Registration are hardening mobile security and immediate access to external APIs. There are multiple ways to manage DCR securely, and the options chosen will depend on your scenarios, though the most secure solutions are based on public key cryptography.

Authentication is done by either getting an initial DCR access token with a dcr scope, or using Mutual TLS for the main DCR registration request. The capabilities described in this article are part of your security toolbox and should be provided by your Identity and Access Management (IAM) system.