Contents
Client registration
Dynamic Client Registration (RFC 7591). Anonymous by design (as required by the MCP
authorization spec): the guard rails are on the metadata — https (or loopback) redirect URIs,
authorization code grant only, a fixed set of scopes. Self-registered clients are always
treated as third-party: the user approves them on a consent screen. Self-registered clients see the consent screen the first time, and again whenever the person has no valid token of that client covering the requested scopes; send prompt=consent to always show it.
Base URL, authentication and conventions of this API are on the OAuth & OpenID Connect API page.
/oauth/registerRegister an OAuth client dynamically
RFC 7591 Dynamic Client Registration. No authentication: any client can register, the user's consent is what protects the account.
Rules applied to the metadata:
redirect_urisis required, 1 to 5 absolute URIs,httpsonly —httpis accepted only for loopback hosts (localhost,127.0.0.1,[::1], RFC 8252). No fragment, no*. Duplicates are removed.grant_typesdefaults to["authorization_code"]; onlyauthorization_codeandrefresh_tokenare accepted andauthorization_codemust be present.refresh_tokenis always added.response_typesmay only containcode.token_endpoint_auth_methoddefaults tonone(public client + PKCE, as MCP connectors work).client_secret_postorclient_secret_basicmake it a confidential client and the response includes aclient_secretthat never expires — it is shown only once.scopeis filtered (not rejected) to the supported set; when nothing valid is requested you get all of them.nucleo.ai_toolsis always added.client_nameis stripped of HTML and cut to 120 characters (default: the host of the first redirect URI);client_uriis cut to 250 characters. Other RFC 7591 fields are ignored.
Every call creates a new client (not idempotent). Clients registered here are third-party
and their tokens are limited to the AI tools (nucleo.ai_tools). Self-registered clients see the consent screen the first time, and again whenever the person has no valid token of that client covering the requested scopes; send prompt=consent to always show it.
Rate limit: 10 requests per minute per IP address. Over the limit the answer is 429 with a
JSON OAuth error (error: rate_limited), Retry-After and the CORS headers of the other
responses.
Request bodyapplication/json
redirect_urisarray of string (uri)requiredhttps, orhttpon loopback only. No fragment, no wildcard.min items 1max items 5client_namestringShown on the consent screen. HTML is stripped.
max length 120client_uristring (uri)max length 250grant_typesarray of stringOne ofauthorization_coderefresh_tokendefault ["authorization_code"]response_typesarray of stringOne ofcodedefault ["code"]token_endpoint_auth_methodstringOne ofnoneclient_secret_postclient_secret_basicdefault nonescopestringSpace-separated; filtered to the supported scopes.
default openid profile email
Responses
201Client created.application/json
HeadersAccess-Control-Allow-Origin
client_idstringrequiredclient_id_issued_atintegerrequiredUnix timestamp.
client_secretstringConfidential clients only. Shown once.
client_secret_expires_atinteger0 = never expires.
One of0client_namestringredirect_urisarray of string (uri)requiredgrant_typesarray of stringrequiredresponse_typesarray of stringrequiredtoken_endpoint_auth_methodstringrequiredscopestringrequired
400Invalid client metadata (RFC 7591 §3.2.2 error response).application/json
HeadersAccess-Control-Allow-Origin
errorstringrequiredOne ofinvalid_redirect_uriinvalid_client_metadataerror_descriptionstring
429Rate limit exceeded. JSON OAuth error (RFC 6749 §5.2 format), whatever the
Acceptheader.application/jsonHeadersRetry-AfterX-RateLimit-LimitX-RateLimit-Remaining
errorstringrequiredOne ofrate_limitederror_descriptionstring
curl -X POST https://auth.nucleoplatform.com/oauth/register \
-H 'Content-Type: application/json' \
-d '{
"client_name": "Acme Assistant",
"redirect_uris": [
"https://assistant.acme.example/oauth/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "none",
"scope": "openid profile email offline_access"
}'const res = await fetch("https://auth.nucleoplatform.com/oauth/register", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"client_name": "Acme Assistant",
"redirect_uris": [
"https://assistant.acme.example/oauth/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "none",
"scope": "openid profile email offline_access"
}),
});
const data = await res.json();
console.log(res.status, data);<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$response = $client->request('POST', 'https://auth.nucleoplatform.com/oauth/register', [
'json' => [
'client_name' => 'Acme Assistant',
'redirect_uris' => [
'https://assistant.acme.example/oauth/callback',
],
'grant_types' => [
'authorization_code',
'refresh_token',
],
'response_types' => [
'code',
],
'token_endpoint_auth_method' => 'none',
'scope' => 'openid profile email offline_access',
],
'http_errors' => false,
]);
echo $response->getStatusCode(), PHP_EOL;
echo $response->getBody();{
"client_id": "9d3f2b1c-6a4e-4f7b-9c2d-1e8a7b6c5d4f",
"client_id_issued_at": 1791100800,
"client_name": "Acme Assistant",
"redirect_uris": [
"https://assistant.acme.example/oauth/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "none",
"scope": "openid profile email offline_access nucleo.ai_tools"
}{
"client_id": "9d3f2b1c-7b5f-4a8c-8d3e-2f9b8c7d6e5a",
"client_id_issued_at": 1791100800,
"client_secret": "s3cr3tExampleValueOnlyShownOnce000000000",
"client_secret_expires_at": 0,
"client_name": "Acme Reporting",
"redirect_uris": [
"https://reports.acme.example/auth/nucleo/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "client_secret_basic",
"scope": "openid email nucleo.ai_tools"
}{
"error": "invalid_redirect_uri",
"error_description": "redirect_uris is required and must be a non-empty array."
}{
"error": "invalid_redirect_uri",
"error_description": "Too many redirect_uris (max 5)."
}{
"error": "invalid_redirect_uri",
"error_description": "redirect_uris must use https (http is allowed only for loopback addresses)."
}{
"error": "invalid_redirect_uri",
"error_description": "redirect_uris must not contain a fragment."
}{
"error": "invalid_redirect_uri",
"error_description": "Wildcards are not allowed in redirect_uris."
}{
"error": "invalid_client_metadata",
"error_description": "Unsupported grant_types: client_credentials. Only authorization_code and refresh_token are supported."
}{
"error": "invalid_client_metadata",
"error_description": "Only the \"code\" response_type is supported."
}{
"error": "invalid_client_metadata",
"error_description": "Unsupported token_endpoint_auth_method."
}{
"error": "rate_limited",
"error_description": "Too many requests. Retry after 42 seconds."
}/oauth/registerCORS preflight for client registration
Lets browser-based clients register themselves. Always answers 204 with permissive CORS headers.
Responses
204Preflight accepted.
HeadersAccess-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers
curl -X OPTIONS https://auth.nucleoplatform.com/oauth/registerconst res = await fetch("https://auth.nucleoplatform.com/oauth/register", {
method: "OPTIONS",
});
const data = await res.json();
console.log(res.status, data);<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$response = $client->request('OPTIONS', 'https://auth.nucleoplatform.com/oauth/register', [
'http_errors' => false,
]);
echo $response->getStatusCode(), PHP_EOL;
echo $response->getBody();HTTP 204 — Preflight accepted.