Dynamic Client Registration is a protocol that allows OAuth client applications to register with an OAuth server. It is standardized by both the OpenID Foundation and by the IETF as RFC 7591. These specifications define how a client may submit a request to register itself and the response that the OAuth server should provide.
In this introduction, we will explain when Dynamic Client Registration is useful, what the protocol entails, and a brief overview of how it can be used in the Curity Security Server.
- The Client makes a POST request to the OAuth Server with the Bootstrap access token and the client request data
- The Server issues a new client based on the request and responds with the client details
There are two primary use cases for Dynamic Client Registration:
- Mobile application instances register to get an installation-specific credential
- Clients are registered with the OAuth server from a developer portal or API management system
The first case comes up when an iOS, Android, and other kind of native app is installed on a user’s device. At that time, it will register itself to get a client ID and secret that is unique to that installation. This is important because any such credential that is compiled into and distributed with the app is not truly secret. It can be extracted from the application with relative ease.
By registering for an installation-specific client ID and secret instead, the app can be treated as a confidential client. Being able to keep a credential secret is a requirement imposed by the OAuth standard to issue a refresh token. Without this, the mobile app needs the user to re-authenticate every time its access token expired resulting in a very poor User Experience (UX).
Consequently, non-confidential mobile clients are usually given a refresh token despite the security risks. By using Dynamic Client Registration, this compromise does not need to be made.
In the other case, admins use a portal of some sort to register new apps that will consume APIs. This portal is usually provided by an API gateway (e.g., Apigee). In this case, the API consumer needs to be registered with the OAuth server, so that it can get its users logged in and obtain tokens from the OAuth server.
Because token issuance is provided by Curity and not the gateway, the latter needs to register itself and get a client ID and secret that developers can use in their app. Curity’s admin REST API can be used for this purpose (and is actually preferable in many cases), but Dynamic Client Registration provides a standard API that most gateways support out of the box.
There are many ways in which Dynamic Client Registration can be deployed. The specification focuses on the request and response, and does not cover the entire system architecture. It also does not specify how a client may obtain a token required to register itself, just that authentication may be required if needed. For this reason, a high-level overview of the architecture and flow is needed before looking at the actual request/response of the protocol.
To see how the protocol can be used, it is important to know that there are different configurations or deployments that are possible. In Curity, there are four ways that Dynamic Client Registration can be configured (from the least secure to the most):
- Open Registration: Dynamic Client Registration can be enabled and any client can register without authentication. This is the most promiscuous setting and is typically only used for testing or very open ecosystems. This case is very rare, and won’t be discussed further in this overview.
- Client Authenticated Registration: This is only allowed for clients that have an initial access token that was obtained using the client credential flow. In this case, only the identity of the client is verified — not the user.
- User Authenticated Registration: Client registration is restricted to applications that have an initial access token obtained after a user has authenticated. In this case, the client is identified but only the end user is verified.
- No Registration: It can be completely disabled (per OAuth profile). This is the default in Curity.
The two cases to understand more deeply are Client Authenticated Registration and User Authenticated Registration.
Client Authenticated Registration is useful when the user does not have an account and cannot create one using self-service signup methods during the login process, or there is no user to begin with.
This might be the case for an employee app where the new hire’s account can only be created using some kind of back-office system. In such cases, the client can use an ID and secret which are compiled into it, obtaining an initial access token that is then usable for register.
To obtain this initial access token, the app uses the client credential flow. The identity of that app is verified, but the level of assurance in that app’s identity is quite low. Consequently, this deployment option does not provide confidence that the app really is the expected one and not an impostor that has decompiled the actual one. In effect, this configuration creates a sort of “speed bump” to the first option of open registration. Having said that, if access to the app is restricted (e.g., via an MDM system that only employees can access), it could be secure enough.
The third option is the one that is typically used when distributing an app to customers, partners, or a broad user base. In this setup, the app is distributed with only a client ID. It provides this during user authentication to identity itself, but the app is not actually authenticated. Instead, the user authenticate themselves. This is done using the implicit flow or the assisted token flow. (The code flow can also be used if it’s understand that the client secret used in that flow isn’t really a secret since it’s compiled into the app.) In these cases, the user must login and the app identifies itself. After doing so, an initial access token is issued to the app. As in the second case, this initial access token can then be used by the app to dynamically register itself.
Single Sign-OnWhen the user authenticates, a Single Sign-on (SSO) cookie will be saved. This is important because the app will perform another flow after it has registered and the user cannot be prompted to login again at that point, just a few seconds after the first.
In either of these two cases, the client application obtains an initial access token. This first token is used only for registering a specific instance of the application. To limit this token’s usage, it has a special scope called
dcr. This scope is included because the application asks for it when performing the client credential flow or one of the flows that authenticates the user.
Warning 'DCR Scope'
If the application does not ask for the
dcr scope, the resulting token will not include it and the app will not be able to register itself.
With an initial access token in hand, the client can register itself. To do so, it will make an API call to Curity’s Dynamic Client Registration endpoint. This endpoint is protected and requires an OAuth access token to be presented in the
Authorization request header using the
bearer authentication scheme (per RFC 6750). What is included in the request body depends on how dynamic clients are registered:
- As instances of existing clients where the existing one functions as a sort of template for the dynamically registered one
- As entirely new clients
These often correspond to the first two primary use cases described above but they need not.
Template clients are convenient because all the registration call needs to contain is the id of the template to use. The result will be a client based on that template. This greatly simples administration, as all dynamic clients can be updated as a whole. If the configuration of the template changes (e.g., authentication requirements, redirect URI(s), allowed scopes, etc.), then all dynamic clients based on that client are immediately updated.
The template clients are defined in the Curity Identity Server’s configuration. Each instance of the template will receive a unique client id and a unique client secret.
When registering instances of a native app as in the first use case above, this can be very helpful since only the client ID and secret will vary per installation.
Non-template clients are not based on configured templates. Here the registration needs to contain all the parameters required for the new client to be instantiated.
If the client needs a unique set of properties this is the appropriate choice for DCR.
This setup is suitable for setups where the properties of the clients are not known on beforehand, such as when registering clients through a developer portal.
In this introduction, you got an architectural overview of dynamic client registration. There’s a lot more to learn about and dig into regarding DCR. For instance, all of these resources will give you a deeper understanding of using this feature and how to set it up in Curity:
- Using Dynamic Client Registration
- Dynamic Client Registration video tutorial
- OpenID Connect Curity Documentation
- Tutorial: Integrating Curity with Apigee
- OpenID Connect registration specification
If you take the time to learn more about DCR, you will be rewarded with a safer and more dynamic network. Using DCR, you can better manage the security risks around distributing applications. To this end, Curity provides a templatized approach to dynamic client administration. Also using the various authentication options for client registration, you can create a flexible system that doesn’t expose your organization to vulnerabilities.