Token Exchange (RFC 8693)
Il Problema: Un Token Non Va Bene per Tutto
In un’applicazione monolitica, un singolo token di accesso è sufficiente. Ma le architetture moderne non sono monolitiche. Una tipica richiesta può attraversare più servizi:
Utente → Frontend → API Gateway → Order Service → Payment Service → Notification ServiceOgni servizio in questa catena ha diversi livelli di trust, diversi scope e diversi audience. Usare lo stesso token ovunque crea problemi:
| Problema | Descrizione |
|---|---|
| Token con troppi privilegi | Il token del frontend ha read:users write:orders manage:payments ma il Payment Service ha solo bisogno di process:payments. Se il Payment Service viene compromesso, l’attaccante ha accesso a tutti gli scope. |
| Audience sbagliato | Un token emesso per frontend-app non dovrebbe essere accettato da payment-service. |
| Impersonazione | Un admin deve eseguire il debug dell’account di un utente agendo come quell’utente. Non c’è modo standard di “diventare” un altro utente senza conoscere le sue credenziali. |
| Delega | Il Servizio A deve chiamare il Servizio B per conto dell’utente, ma il Servizio B ha bisogno di conoscere sia l’utente originale che l’identità del servizio chiamante. |
Come Funziona il Token Exchange
La Richiesta di Token Exchange
Una richiesta di token exchange è un POST al token endpoint standard con grant_type=urn:ietf:params:oauth:grant-type:token-exchange:
POST /api/auth/token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=eyJhbGciOiJSUzI1NiJ9...
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&requested_token_type=urn:ietf:params:oauth:token-type:access_token
&audience=payment-service
&scope=process:payments
&actor_token=eyJhbGciOiJSUzI1NiJ9...
&actor_token_type=urn:ietf:params:oauth:token-type:access_tokenParametri della Richiesta
| Parametro | Obbligatorio | Descrizione |
|---|---|---|
grant_type | Sì | Sempre urn:ietf:params:oauth:grant-type:token-exchange |
subject_token | Sì | Il token da scambiare — rappresenta l’identità della parte per conto della quale viene fatta la richiesta |
subject_token_type | Sì | Il tipo del subject token |
requested_token_type | Opzionale | Il tipo desiderato per il token di output. Default: access_token. |
audience | Opzionale | Il servizio o API di destinazione che consumerà il nuovo token |
scope | Opzionale | Gli scope richiesti per il nuovo token. Deve essere un sottoinsieme degli scope del subject token. |
actor_token | Opzionale | Il token della parte che esegue lo scambio (l‘“attore”) |
Impersonazione vs Delega
Impersonazione
Nell’impersonazione, il claim sub del token scambiato è impostato sull’utente target. Il servizio downstream vede le richieste “da” l’utente impersonato. L’attore originale è registrato nel claim act per scopi di audit.
{
"sub": "user-123",
"iss": "https://auth.example.com",
"aud": "frontend-app",
"exp": 1739882700,
"act": {
"sub": "admin-456"
}
}Caso d’uso: Un admin deve riprodurre un bug che riguarda solo l’account di un utente specifico.
Delega
Nella delega, il claim sub del token scambiato rimane l’utente originale. L’attore è registrato nel claim act, ma il token rappresenta ancora la richiesta dell’utente originale, ora mediata da un servizio.
{
"sub": "user-123",
"iss": "https://auth.example.com",
"aud": "payment-service",
"exp": 1739882700,
"scope": "process:payments",
"act": {
"sub": "order-service"
}
}Caso d’uso: Chiamate servizio-a-servizio in un’architettura a microservizi.
Differenze Chiave
| Dimensione | Impersonazione | Delega |
|---|---|---|
sub nel nuovo token | Utente target | Utente originale (invariato) |
Claim act | Admin/attore originale | Servizio intermediario |
| Il downstream vede | ”Richiesta da utente target" | "Richiesta da utente originale tramite servizio” |
| Permesso richiesto | impersonate:users | delegate:tokens |
| Livello di rischio | Alto (assunzione completa dell’identità) | Medio (lo scope può essere ridotto) |
L’impersonazione è un’operazione privilegiata. In Auris, solo i client con il permesso impersonate:users possono eseguire scambi di token per impersonazione. Questo permesso non dovrebbe mai essere concesso ai client rivolti agli utenti finali.
Il Claim act: Catene di Delega
Il claim act (attore) è un oggetto JSON incorporato nel JWT che registra chi ha eseguito il token exchange. I claim di attore possono essere annidati per rappresentare una catena di deleghe:
{
"sub": "user-123",
"iss": "https://auth.example.com",
"aud": "notification-service",
"act": {
"sub": "payment-service",
"act": {
"sub": "order-service",
"act": {
"sub": "api-gateway"
}
}
}
}Questo token racconta una storia: user-123 ha fatto una richiesta tramite api-gateway, che ha delegato a order-service, che ha delegato a payment-service, che ora chiama notification-service.
Auris limita la profondità della catena di delega a 5 per default.
Proprietà di Sicurezza
Riduzione Scope (Mai Espansione)
Il token scambiato non può mai avere più permessi dell’originale. Se il subject token ha scope read:users write:orders, il token scambiato può richiedere read:users (sottoinsieme) ma non read:users delete:users (sovrainsieme).
Trail di Audit
Ogni token exchange è registrato con l’identità del subject token, l’identità dell’actor token, audience e scope richiesti, tipo di scambio, indirizzo IP e timestamp.
Riduzione del Lifetime del Token
I token scambiati hanno sempre un lifetime più breve del token originale. Il default è il 50% del lifetime rimanente del subject token.
Dettagli di Configurazione
Token Exchange è abilitato per applicazione nella Console Auris sotto Applicazioni > (seleziona applicazione) > Impostazioni:
| Impostazione | Default | Descrizione |
|---|---|---|
| Abilita Token Exchange | false | Toggle principale |
| Consenti impersonazione | false | Se questa applicazione può eseguire scambi di impersonazione |
| Consenti delega | false | Se questa applicazione può eseguire scambi di delega |
| Profondità massima catena | 5 | Profondità massima di annidamento dei claim act |
| Lifetime token scambiato | 50% | Lifetime del token scambiato come percentuale del lifetime rimanente del subject token |
Esempio di Codice: Catena di Delega tra Microservizi
// api-gateway riceve il token dell'utente e deve chiamare order-service
async function callOrderService(userAccessToken: string) {
const exchangeResponse = await fetch('https://auth.example.com/api/auth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
subject_token: userAccessToken,
subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',
audience: 'order-service',
scope: 'read:orders write:orders',
}),
})
const { access_token: orderServiceToken } = await exchangeResponse.json()
return fetch('https://order-service.internal/api/orders', {
headers: { Authorization: `Bearer ${orderServiceToken}` },
})
}Ogni token exchange — sia impersonazione che delega — crea una voce nel log di audit di Auris. Gli amministratori possono filtrare i log per tipo di scambio per rivedere tutta l’attività di impersonazione. In ambienti ad alta sicurezza, gli eventi di impersonazione possono innescare notifiche in tempo reale al team di sicurezza.
Concetti Correlati
- Token Spiegati — Struttura JWT, il claim
acte i lifetime dei token - OAuth 2.0 & OIDC — Il framework di autorizzazione che Token Exchange estende
- FGA / Modello Zanzibar — Autorizzazione fine-grained che può controllare i permessi di impersonazione
- DPoP (Proof of Possession) — Token sender-constrained combinabili con Token Exchange