Let clients register themselves (DCR)
This guide lets apps you don’t build register themselves as clients, and shows you how to keep an eye on what registered.
Some apps can’t be set up by hand. A command-line tool or an AI assistant connecting through MCP (the Model Context Protocol) is installed by its users, each copy on its own machine, and expects to get a client of its own. Dynamic client registration (DCR) lets it: the app calls POST /connect/register, as RFC 7591 defines, and gets a client identifier back, with nobody creating it in the admin console.
Let clients register themselves
Section titled “Let clients register themselves”-
In the admin console, open Admin, General, turn on Dynamic client registration enabled, and save.
-
Limit who can reach
/connect/register. While DCR is on, anyone who can reach it can create a client, with no token and no sign-in. Turn on the rate limiter withGOIABADA_AUTHSERVER_RATELIMITER_ENABLED, which then allows 10 registrations a minute from each IP address, or limit the endpoint at your reverse proxy. See rate limits. -
Check that the auth server now advertises it. The discovery document carries
registration_endpoint, which is how an app finds out it may register:Terminal window curl https://auth.example.com/.well-known/openid-configuration{"issuer": "https://auth.example.com","registration_endpoint": "https://auth.example.com/connect/register"}That’s two fields of many. While DCR is off,
registration_endpointisn’t there.
Register your app
Section titled “Register your app”If you’re writing the tool, this is what it does the first time it runs.
-
Read
registration_endpointfrom the discovery document. If it isn’t there, the auth server doesn’t take registrations: ask its administrator for a client instead. -
Register, naming your app and where the browser comes back to. A tool on the user’s machine is a public client, with no secret, and receives its callback on a loopback address:
POST /connect/register HTTP/1.1Host: auth.example.comContent-Type: application/json{"client_name": "Report builder","redirect_uris": ["http://127.0.0.1/callback"],"token_endpoint_auth_method": "none","grant_types": ["authorization_code", "refresh_token"]} -
Keep the
client_idfrom the answer. It’s yours for good: there’s no endpoint to read or change a registration later, so register again only if you lose it.HTTP/1.1 201 CreatedContent-Type: application/jsonCache-Control: no-store{"client_id": "dcr_6f1c2a9e-3b7d-4e0a-9c55-2d8b1e4f7a10","client_id_issued_at": 1759900000,"client_secret_expires_at": 0,"redirect_uris": ["http://127.0.0.1/callback"],"token_endpoint_auth_method": "none","grant_types": ["authorization_code", "refresh_token"],"client_name": "Report builder"} -
Sign the user in with the authorization code flow and PKCE, as Add sign-in to a SPA or mobile app shows. Start a local server on any free port and send that port in
redirect_uri, such ashttp://127.0.0.1:53682/callback: for a loopback address the port isn’t compared.
Review what registered
Section titled “Review what registered”-
Open Admin, Clients. Each client that registered itself carries a Self-registered badge.
-
Open one you recognize and fix how your users see it. On the Settings tab, give it a Display name and turn on Show display name, which replaces the name it gave itself and the consent screen’s note that it hasn’t been verified. Once you trust it, you can turn Consent required off.
-
For one you don’t recognize, untick Enabled to stop it signing anyone in, or delete it from the list.
Every registration leaves a dynamic_client_registration entry in the audit log, with the new client, its grant types, whether it’s public, and the IP address it came from.
What a registration may ask for
Section titled “What a registration may ask for”The auth server reads four fields, redirect_uris, token_endpoint_auth_method, grant_types and client_name, and ignores the rest. A registration can’t ask for the legacy flows, and a public client can’t ask for client_credentials. Redirect URIs follow stricter rules than for clients you create, since nobody has checked who’s asking: a public client gets loopback http and custom schemes such as myapp://callback, and a confidential one https and loopback http. So a single-page app can’t register itself: create it in the admin console. Dynamic client registration has every field, rule and error.
What a self-registered client gets
Section titled “What a self-registered client gets”It’s enabled straight away, with an identifier made up of dcr_ and a UUID that can’t be changed later. Consent is on, its ACR level is urn:goiabada:level2_optional, and a public one always uses PKCE. A confidential one gets a secret, which the answer carries once, and which an administrator can read later on the client’s Authentication tab. The implicit flow and ROPC are off on the client itself, so turning either on globally doesn’t reach it. Its token lifetimes are copied from the server’s settings when it registers. Apart from its identifier, an administrator can change any of it like any other client’s. See Self-registered clients.
Turning it off
Section titled “Turning it off”Turning Dynamic client registration enabled off stops new registrations: /connect/register answers 403 with access_denied, and discovery stops carrying registration_endpoint. Clients that already registered keep working. To stop one, disable or delete it.