Nota sul redirect-uri: deve essere l'URL dell'applicazione esterna che gestisce la callback OAuth, non un URL di Cuborio. E' l'indirizzo a cui l'utente viene reindirizzato dopo aver autorizzato l'accesso, e deve corrispondere a quello che l'applicazione esterna invia nel parametro redirect_uri durante il flusso di autorizzazione.
Il client_secret viene mostrato una sola volta. E' hashato in database con bcrypt e non e' recuperabile. Se perso, occorre revocare il client e crearne uno nuovo.
Elencare i client
Revocare un client
2. Endpoint disponibili
Endpoint
Metodo
Descrizione
/.well-known/oauth-authorization-server
GET
Discovery metadata (RFC 8414)
/.well-known/oauth-protected-resource
GET
Protected resource metadata MCP (RFC 9728)
/authorize
GET
Pagina di consenso utente
/authorize
POST
Approvazione/rifiuto consenso
/token
POST
Scambio code per token / refresh
/revoke
POST
Revoca token (RFC 7009)
L'endpoint di discovery restituisce automaticamente tutti gli URL:
3. Flusso di autorizzazione (authorization_code + PKCE)
Il flusso OAuth 2.1 con PKCE si compone di 4 passi.
Passo 1 — Generare il PKCE code verifier e challenge
Il client genera un code_verifier casuale (43-128 caratteri URL-safe) e calcola il code_challenge con SHA-256:
Passo 2 — Redirect dell'utente alla pagina di consenso
Aprire nel browser dell'utente:
Parametro
Obbligatorio
Descrizione
response_type
Si
Sempre code
client_id
Si
Il client ID ottenuto alla creazione
redirect_uri
Si
Deve corrispondere esattamente a quello registrato
state
Si
Stringa casuale anti-CSRF, verificata dal client al ritorno
code_challenge
Si
Challenge PKCE calcolato al passo 1
code_challenge_method
Si
Sempre S256
scope
No
Default: mcp:tools
L'utente vede una pagina di consenso con il nome dell'applicazione e puo' autorizzare o negare.
Passo 3 — Ricevere l'authorization code
Dopo l'approvazione, l'utente viene reindirizzato a:
Verificare sempre che state corrisponda a quello inviato al passo 2.
Se l'utente nega, il redirect contiene error=access_denied.
Passo 4 — Scambiare il code per i token
In alternativa alle credenziali nel body, si puo' usare HTTP Basic Auth:
Risposta:
4. Usare l'access token
Includere il token nell'header Authorization di ogni richiesta API:
5. Rinnovare l'access token
L'access token scade dopo 1 ora (configurabile). Prima della scadenza, usare il refresh token per ottenerne uno nuovo:
Risposta: stessa struttura del passo 4, con nuovi access_token e refresh_token.
Refresh token rotation: ad ogni refresh, il vecchio refresh token viene revocato e ne viene emesso uno nuovo. Non riutilizzare il vecchio.
6. Revocare un token
Per disconnettere l'applicazione (logout), revocare il token:
Si puo' passare sia un access token che un refresh token. La revoca e' sempre a cascata: revocando uno si revoca anche l'altro della coppia. La risposta e' sempre 200 OK (RFC 7009).
7. Scadenze e configurazione
Parametro
Default
Variabile d'ambiente
Access token TTL
1 ora (3600s)
OAUTH_ACCESS_TOKEN_TTL
Refresh token TTL
30 giorni (2592000s)
OAUTH_REFRESH_TOKEN_TTL
Authorization code TTL
10 minuti (600s)
OAUTH_AUTH_CODE_TTL
8. Gestione degli errori
Tutte le risposte di errore seguono il formato standard OAuth 2.1:
L'utente ha negato il consenso (redirect, non JSON)
9. Esempio completo (PHP)
10. Sicurezza
PKCE obbligatorio: non e' possibile ottenere token senza code_challenge + code_verifier (S256).
Authorization code monouso: un secondo utilizzo restituisce invalid_grant.
Refresh token rotation: ogni refresh invalida il token precedente.
Token hashati: access token, refresh token e authorization code sono salvati in database come hash SHA-256. I valori in chiaro esistono solo nella risposta HTTP.
Client secret hashato: salvato con bcrypt, non recuperabile.
Revoca a cascata: revocare un access token revoca anche il refresh associato, e viceversa.
Constant-time comparison: tutti i confronti di token usano hash_equals per prevenire timing attacks.