Contents
Tokens
Token endpoint and token revocation. Access tokens and ID tokens are RS256 JWTs signed with the key
published in the JWKS; access tokens last 8 hours, ID tokens 1 hour. Refresh tokens last
30 days. Access token claims: aud (your client_id), jti, iat, nbf, exp, sub,
scopes and org_id (the company passed to /oauth/authorize, or null; userinfo returns
the same value).
Base URL, authentication and conventions of this API are on the OAuth & OpenID Connect API page.
/oauth/tokenExchange a code or refresh a token
Standard OAuth 2.0 token endpoint (application/x-www-form-urlencoded or JSON).
Rate limits, per minute, counted per client (client_id): 10 exchanges of the same
authorization code, 30 uses of the same refresh token, 60 other requests per client and IP;
on top of that, at most 1,200 requests per IP. Over a limit the answer is 429 with a JSON
OAuth error (error: rate_limited) and Retry-After: wait that many seconds before retrying.
- authorization_code: send
code,redirect_uri(same as in the authorize request),client_id, andcode_verifier(PKCE). Confidential clients also authenticate withclient_secret(body) or HTTP Basic. - refresh_token: send
refresh_tokenandclient_id(plus secret for confidential clients). A new refresh token is returned and the previous one is revoked — always store the latest one. - There is no
client_credentialsgrant: every token acts for a person.
ID token. When the granted scope includes openid, the authorization_code exchange also
returns id_token: an RS256 JWT signed with the JWKS key (kid in the header), valid for 1 hour.
Claims: iss (https://auth.nucleoplatform.com), sub (same as userinfo), aud and azp
(your client_id), iat, exp, jti, auth_time (when the person signed in to Nucleo), and
nonce if you sent one to /oauth/authorize. With email: email, email_verified. With
profile: name, locale, and picture when the person has an avatar. The refresh exchange
does not return a new ID token: keep the one from sign-in. An ID token is not an access token —
sending it as Bearer gets 401.
Lifetimes: access token 8 hours (expires_in: 28800), refresh token 30 days. For
self-registered clients the granted scope always includes nucleo.ai_tools.
Company of the token. The access token carries org_id: the company passed as org_id to
/oauth/authorize (when the person belongs to it), kept by every refresh, or null. The
password grant and tokens issued before this claim existed have null or no org_id.
Request bodyapplication/x-www-form-urlencoded, application/json
grant_typestringrequiredOne ofauthorization_coderefresh_tokenclient_idstringrequiredclient_secretstringConfidential clients using
client_secret_post.codestringauthorization_code only.
redirect_uristring (uri)authorization_code only; must equal the one used at
/oauth/authorize.code_verifierstringPKCE verifier; required when a
code_challengewas sent.min length 43max length 128refresh_tokenstringrefresh_token only.
scopestringOptional; on refresh it may only narrow the original scope.
Responses
200Tokens issued.application/json
token_typestringrequiredOne ofBearerexpires_inintegerrequiredExample:28800access_tokenstringrequiredRS256 JWT.
refresh_tokenstringid_tokenstringRS256 JWT (OpenID Connect ID token). Only on the
authorization_codeexchange when the scope includesopenid. Claims are described inIdTokenClaims.
400Invalid request, grant or scope.application/json
errorstringrequiredOne ofinvalid_requestinvalid_clientinvalid_grantunauthorized_clientunsupported_grant_typeinvalid_scopeaccess_deniederror_descriptionstringhintstring
401Client authentication failed.application/json
errorstringrequiredOne ofinvalid_requestinvalid_clientinvalid_grantunauthorized_clientunsupported_grant_typeinvalid_scopeaccess_deniederror_descriptionstringhintstring
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/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode grant_type=authorization_code \
--data-urlencode client_id=9d3f2b1c-6a4e-4f7b-9c2d-1e8a7b6c5d4f \
--data-urlencode redirect_uri=https://assistant.acme.example/oauth/callback \
--data-urlencode code=def50200a1b2c3 \
--data-urlencode code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXkconst res = await fetch("https://auth.nucleoplatform.com/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
grant_type: "authorization_code",
client_id: "9d3f2b1c-6a4e-4f7b-9c2d-1e8a7b6c5d4f",
redirect_uri: "https://assistant.acme.example/oauth/callback",
code: "def50200a1b2c3",
code_verifier: "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
}),
});
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/token', [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => '9d3f2b1c-6a4e-4f7b-9c2d-1e8a7b6c5d4f',
'redirect_uri' => 'https://assistant.acme.example/oauth/callback',
'code' => 'def50200a1b2c3',
'code_verifier' => 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk',
],
'http_errors' => false,
]);
echo $response->getStatusCode(), PHP_EOL;
echo $response->getBody();{
"token_type": "Bearer",
"expires_in": 28800,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiI5ZDNmMmIxYy02YTRlIiwic3ViIjoiNDIiLCJzY29wZXMiOlsib3BlbmlkIiwibnVjbGVvLmFpX3Rvb2xzIl19.signature",
"refresh_token": "def50200f9e8d7c6b5a4",
"id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjNyTDF4MGRYcTZtMHlCcUgybDd4WnI5bjBicThmNGsxczJ2SnQ4bzVwV2MifQ.eyJpc3MiOiJodHRwczovL2F1dGgubnVjbGVvcGxhdGZvcm0uY29tIiwic3ViIjoiNDIiLCJhdWQiOiI5ZDNmMmIxYy02YTRlLTRmN2ItOWMyZC0xZThhN2I2YzVkNGYiLCJhenAiOiI5ZDNmMmIxYy02YTRlLTRmN2ItOWMyZC0xZThhN2I2YzVkNGYiLCJpYXQiOjE3OTExMDA4MDAsImV4cCI6MTc5MTEwNDQwMCwianRpIjoiMGI2ZjFkMmUtNGMzYS00ZThiLTlmN2QtMmExYzNlNWI3ZDlmIiwiYXV0aF90aW1lIjoxNzkxMTAwNzUwLCJub25jZSI6Im4tMFM2X1d6QTJNaiIsImVtYWlsIjoiZ2l1bGlhLnJvc3NpQGFjbWUuZXhhbXBsZSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlfQ.signature"
}{
"error": "invalid_grant",
"error_description": "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.",
"hint": "Failed to verify `code_verifier`."
}{
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}{
"error": "invalid_client",
"error_description": "Client authentication failed"
}{
"error": "rate_limited",
"error_description": "Too many requests. Retry after 42 seconds."
}/api/auth/revokeRevoke the current access token
Revokes the access token sent in Authorization and every refresh token issued with it
(sign-out / disconnect). Idempotent from the client's point of view: a revoked token then
answers 401, on the MCP connector immediately as well. Available to self-registered clients'
tokens. The confirmation message is currently returned in Italian.
This is the only way to revoke a token: there is no RFC 7009 revocation endpoint, and the discovery
documents carry no revocation_endpoint. It revokes the token you authenticate with, never another
one.
Responses
200Token revoked.application/json
messagestring
401Missing, expired or revoked access token.application/json
messagestring
curl -X POST https://auth.nucleoplatform.com/api/auth/revoke \
-H "Authorization: Bearer $NUCLEO_ACCESS_TOKEN" \
-H 'Accept: application/json'const res = await fetch("https://auth.nucleoplatform.com/api/auth/revoke", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.NUCLEO_ACCESS_TOKEN}`,
Accept: "application/json",
},
});
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/api/auth/revoke', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('NUCLEO_ACCESS_TOKEN'),
'Accept' => 'application/json',
],
'http_errors' => false,
]);
echo $response->getStatusCode(), PHP_EOL;
echo $response->getBody();{
"message": "Token revocato."
}{
"message": "Unauthenticated."
}