---
title: "OIDC spiegato con Zitadel: organizzazioni, progetti, grant e audience"
description: "Il modello di identità di Zitadel spiegato davvero: istanza, organizzazione, progetto, applicazione, ruoli e grant, e perché l'audience del token cambia tutto."
canonical: "https://www.mauriziofonte.it/blog/post/zitadel-oidc-organizzazioni-progetti-grant-audience.html"
author: "Maurizio Fonte"
date: "2026-07-27T16:21:37+02:00"
modified: "2026-07-27T16:21:37+02:00"
section: "IAM & SSO"
tags: ["IAM & SSO", "API Design"]
license: "Riuso e citazione consentiti con attribuzione e link alla fonte"
---

[IAM & SSO](https://www.mauriziofonte.it/blog/cat/iam-sso.html) [API Design](https://www.mauriziofonte.it/blog/cat/api-design.html)

# [OIDC spiegato con Zitadel: organizzazioni, progetti, grant e audience](https://www.mauriziofonte.it/blog/post/zitadel-oidc-organizzazioni-progetti-grant-audience.html)

Lunedì 27 Luglio 2026, alle 16:21 ![OIDC spiegato con Zitadel: organizzazioni, progetti, grant e audience](https://www.mauriziofonte.it/image/005450200-zitadel-oidc-organizzazioni-progetti-grant-audience.jpg)

Un identity provider self-hosted non è difficile da installare. È difficile da modellare. Ho visto impianti Zitadel funzionanti al primo login e completamente sbagliati nella struttura, con un progetto per ogni applicazione, ruoli duplicati tre volte e un'autorizzazione che nessuno sapeva più dove vivesse. Funzionano finché c'è una sola applicazione. Il giorno in cui ne aggiungi una seconda che deve parlare con la prima, il modello sbagliato presenta il conto, e il conto è sempre lo stesso: **una chiamata autenticata che viene respinta con un errore di audience**, e nessuno capisce perché, visto che il token è valido, la firma è corretta e l'utente ha appena fatto il login.

Questo è il primo di tredici articoli in cui racconto un'integrazione Zitadel reale, portata in produzione fra sistemi che non si somigliano: un identity provider, un gestionale monolitico in Laravel che fa da resource server e da autorità di autorizzazione, un pannello self-service scritto in Node.js e React che scende su una directory LDAP solo come backend dati. Nei prossimi pezzi entrerò nel codice, nell'installazione nativa su Debian, nell'alta disponibilità, nel filtraggio applicativo che sostituisce le ACL di directory e nella revoca dei permessi. Ma nessuno di quei pezzi ha senso se prima non è chiaro il modello mentale, ed è questo il pezzo che lo pianta. Se lo salti, tutto il resto sembrerà arbitrario.

Ho scritto questo articolo perché funzioni su due tavoli. C'è la parte per chi implementa, con gli scope esatti e i claim che finiscono nel token, e c'è la parte per chi la decisione la firma e la paga, perché il modello di identità è una di quelle scelte che sembrano tecniche e invece determinano cosa potrai fare fra due anni senza rifare tutto. Metto anche le mani avanti su un punto, perché in rete circola molta documentazione vecchia: alla data in cui scrivo la versione corrente è la **4.16.1**, e dalla versione 3 Zitadel è distribuito sotto licenza **AGPL 3.0**, non più Apache 2.0. Molte comparative online riportano ancora la licenza sbagliata. Ci torno alla fine, perché cambia la valutazione, non solo la nota a piè di pagina.

## Perché il modello di Zitadel confonde chi arriva da Keycloak o da Auth0?

Perché i nomi coincidono ma i confini no. In Keycloak il contenitore che isola gli utenti si chiama *realm*, e il client OIDC è l'unità a cui assegni ruoli e mapper: il ragionamento naturale diventa "un client, un'applicazione, un perimetro". In Auth0 hai i tenant e le *API* registrate, e l'audience che chiedi è l'identificativo dell'API che vuoi chiamare. In Zitadel il contenitore degli utenti si chiama *organizzazione*, ma l'unità che porta ruoli, autorizzazioni e confine di fiducia **non è l'applicazione: è il progetto**. L'applicazione è solo un client registrato dentro quel progetto.

La traduzione dei termini, che vale la pena tenere sott'occhio le prime settimane:

| Concetto | Keycloak | Auth0 | Zitadel |
| --- | --- | --- | --- |
| Contenitore degli utenti | realm | tenant | organizzazione |
| Perimetro di ruoli e autorizzazioni | client (o realm) | API + ruoli del tenant | progetto |
| Client OIDC registrato | client | application | applicazione |
| Destinatario dichiarato del token | client id | identificativo dell'API | client id, oppure project id via scope |
| Delega a un partner | gruppi e sotto-realm | organizations | project grant |

È una differenza di una parola e cambia l'architettura. Se traduci meccanicamente "client Keycloak" con "applicazione Zitadel" e poi metti ogni applicazione in un progetto suo, hai costruito tanti perimetri isolati quante sono le applicazioni, e due tuoi servizi non potranno più fidarsi l'uno dell'altro senza aggiungere un segreto condiviso, che è esattamente ciò che OAuth2 esiste per evitare.

## I livelli che devi tenere separati in testa

La [documentazione ufficiale sulla struttura delle organizzazioni](https://zitadel.com/docs/concepts/structure/organizations) è precisa e vale la pena leggerla nell'ordine giusto, dal contenitore più grande al più piccolo.

L'*istanza* è il deployment: un binario, un database, un dominio esterno. È il livello a cui esistono le impostazioni globali e il super-amministratore. Se ospiti l'IdP tu, l'istanza è la macchina che gestisci.

L'*organizzazione* è il tenant dentro l'istanza. La documentazione la descrive come il recipiente dove vivono i tuoi progetti e i tuoi utenti, paragonabile a un tenant di un SaaS o a una unità organizzativa in una directory. Ogni organizzazione ha il proprio pool di utenti, umani e macchina, e un **dominio primario** che non è cosmetico: determina il login name mostrato all'utente e finisce asserito dentro gli access token. Un'istanza può contenere molte organizzazioni; per un'azienda singola ne basta una, e usarne di più è utile solo quando servono davvero pool di utenti separati, per esempio quando i dipendenti e i clienti finali non devono nemmeno vedersi come nomi utente.

Il *progetto* è il livello che conta ed è quello che quasi tutti sottovalutano. È il contenitore di tutti i componenti strettamente correlati fra loro, e stabilisce il contesto di sicurezza di una soluzione software. La conseguenza operativa, dritta dalla documentazione: **tutte le applicazioni dentro un progetto condividono le stesse definizioni di ruolo, gli stessi grant e le stesse assegnazioni**. Non è un dettaglio di comodità, è la definizione stessa del confine.

L'*applicazione* è il client: un'app web, un'app mobile, una single-page application, una API. Ha il proprio `client_id`, il proprio metodo di autenticazione, i propri redirect URI. E ha una cosa sola che conta davvero: appartiene a un progetto.

Il *ruolo* vive sul progetto, non sull'applicazione. Ha una chiave, un nome leggibile e un gruppo opzionale. L'*autorizzazione*, che nella console vedi come assegnazione di ruolo, è il legame fra un utente e i ruoli di un progetto.

> Regola pratica che uso quando disegno un impianto nuovo: un progetto per ogni **dominio di fiducia**, non per ogni applicazione. Se due componenti devono potersi chiamare a vicenda presentando un token utente, stanno nello stesso progetto. Se non devono, stanno in progetti diversi, e allora l'isolamento è reale.

## Utenti umani, utenti macchina e la login che dalla versione 4 vive fuori dal binario

Dentro un'organizzazione convivono due popolazioni che si comportano in modo diverso. Gli *utenti umani* hanno una password, eventualmente un secondo fattore, e attraversano il flusso di autorizzazione con il browser. Gli *utenti macchina*, che la console chiama service user, non hanno un browser: si autenticano con una chiave privata o con un token personale e ottengono token tramite flussi server-to-server. Servono per i lavori pianificati, per il provisioning e per tutto ciò che deve agire senza una persona davanti.

Nel progetto da cui viene questa serie gli utenti macchina hanno avuto un ruolo preciso e poco intuitivo: sono stati lo strumento per **verificare le assunzioni prima di scrivere il codice**. Prima di implementare qualunque cosa ho creato un utente macchina usa e getta, ho chiesto un token con lo scope di audience di progetto e ho guardato cosa c'era davvero dentro il claim `aud`. Ci sono voluti dieci minuti e hanno smentito l'assunzione su cui poggiava metà del disegno. Consiglio spassionato: la prima cosa da fare su un IdP nuovo non è scrivere l'integrazione, è **farsi emettere un token e leggerlo**.

C'è poi un fatto strutturale della versione 4 che tocca direttamente il modello mentale. **L'interfaccia di login non è più dentro il binario**: è un'applicazione separata che serve il proprio percorso e dialoga con il core via API, autenticandosi essa stessa come utente macchina con un ruolo dedicato. Detto altrimenti, il primo client del tuo identity provider è la sua stessa pagina di login. Chi installa Zitadel oggi installa **due componenti**, non uno, e il reverse proxy deve smistare le richieste di conseguenza. È il prezzo di una login personalizzabile senza mettere le mani nel core, ed è la ragione per cui in questa serie esiste un [pezzo sull'installazione nativa su Debian](https://www.mauriziofonte.it/blog/post/zitadel-produzione-debian-senza-docker.html): la via ufficiale oggi passa da Docker, la strada binaria funziona ancora ma non la documenta più nessuno.

## Cosa finisce davvero dentro l'audience del token

Qui sta il punto tecnico che fa la differenza fra un impianto che funziona e uno che ti costa una giornata di debug. Quando un'applicazione chiede un access token, per default l'`aud` del token contiene il proprio `client_id`. Va benissimo finché quel token torna solo all'applicazione che lo ha chiesto. Non va più bene nel momento in cui l'applicazione A vuole chiamare un endpoint dell'applicazione B presentando il token dell'utente: B riceve un token la cui audience è il client di A, e se B fa il suo lavoro lo respinge, perché quel token non era destinato a lei.

La risposta di Zitadel è uno scope riservato, documentato nella [pagina degli scope OIDC e OAuth](https://zitadel.com/docs/apis/openidoauth/scopes):

```text
urn:zitadel:iam:org:project:id:{projectId}:aud
```

Aggiungendo quello scope alla richiesta di autorizzazione, l'identificativo del **progetto** viene inserito nell'audience dell'access token. Non il `client_id` di B: il `projectId`. Ed è qui che il modello si chiude su sé stesso. Se A e B stanno nello stesso progetto, B può validare il token controllando che nell'`aud` compaia il proprio `projectId`, che conosce per configurazione. Le due applicazioni non condividono nessun segreto: ognuna ha la propria relazione con l'IdP, ognuna la propria chiave, e ciò che le lega è l'appartenenza allo stesso progetto.

In un'authorize URL reale lo scope si affianca agli altri e il risultato somiglia a questo, con gli identificativi ovviamente inventati:

```text
scope=openid profile email
      urn:zitadel:iam:user:metadata
      urn:zitadel:iam:user:resourceowner
      urn:zitadel:iam:org:id:284419900112233445
      urn:zitadel:iam:org:project:id:284420011223344556:aud
```

Vale la pena sapere cosa fanno gli altri tre, perché sono i più utili in un'integrazione seria. Lo scope `urn:zitadel:iam:org:id:{id}` impone che l'utente appartenga a quella specifica organizzazione: è un controllo lato IdP che ti risparmia un controllo lato applicazione, ed è la difesa più economica contro un utente di un'altra organizzazione che tenta il login sulla tua. Lo scope `urn:zitadel:iam:user:resourceowner` inserisce nel token l'id, il nome e il dominio primario dell'organizzazione dell'utente. Lo scope `urn:zitadel:iam:user:metadata` porta i metadati dell'utente dentro il token, **con i valori codificati in base64**: comodo per trasportare un identificativo interno, ma la codifica non è cifratura, quindi quei metadati vanno trattati come dati di sola lettura gestiti dall'amministratore, mai come qualcosa che l'utente possa modificare. È una distinzione che in una call di progetto ho visto sollevare da un interlocutore non tecnico prima che la sollevasse un tecnico, ed era la domanda giusta.

Un avvertimento che costa caro se lo scopri tardi: perché un'altra applicazione possa validare il token **localmente**, decodificandolo contro le chiavi pubbliche dell'IdP, il tipo di access token dell'applicazione deve essere **JWT** e non opaco. È un'impostazione per applicazione. Con un token opaco la validazione locale semplicemente non esiste. Se vuoi verificare cosa contiene davvero un token che ti sta arrivando, prima di scrivere una riga di codice, puoi incollarlo nel mio [strumento di audit dei JWT](https://www.mauriziofonte.it/strumenti/audit-jwt) e guardare `aud`, `iss` e le scadenze: nove volte su dieci il problema è visibile a occhio nudo in quei tre claim.

Se stai progettando un'integrazione fra due applicazioni che devono fidarsi l'una dell'altra e vuoi che il modello regga anche fra due anni, nel [mio profilo professionale](https://www.mauriziofonte.it/pages/about) trovi il percorso su architetture API, OAuth2 e sistemi multi-tenant da cui arrivano le scelte che descrivo qui.

## Validare il token in locale o interrogare l'IdP a ogni richiesta?

In locale, salvo che tu abbia un requisito esplicito di revoca istantanea del token. La scelta è fra due modi di rispondere alla domanda "questo token è valido": decodificarlo e verificarne la firma contro le chiavi pubbliche pubblicate dall'IdP, oppure chiamare l'endpoint di introspection e chiedere all'IdP di rispondere lui. Sembra un dettaglio implementativo e invece è una decisione di architettura con conseguenze misurabili.

La validazione locale non fa traffico di rete nel percorso critico: scarichi le chiavi pubbliche una volta, le tieni in cache, verifichi firma e scadenze in memoria. Costa microsecondi ed è **disponibile anche quando l'IdP non lo è**, il che significa che un fermo dell'identity provider non propaga immediatamente a tutte le applicazioni che avevano già emesso token validi. L'introspection fa il contrario: una chiamata di rete per ogni richiesta autenticata, latenza aggiunta su ogni singola operazione, e un identity provider che diventa un punto di fallimento sincrono per tutto il sistema.

Il vantaggio dell'introspection è uno solo, ma è reale: risponde alla verità adesso, quindi un token revocato smette di funzionare all'istante, mentre con la validazione locale resta buono fino alla scadenza naturale. La domanda da porsi quindi non è quale delle due sia migliore, ma **quanto vale nel tuo dominio la finestra fra la revoca e la scadenza**. Nell'integrazione da cui viene questa serie ho scelto la validazione locale con una motivazione precisa: il dato davvero critico e revocabile non era il token, era un consenso applicativo, e quel consenso viene riletto dal database a ogni chiamata sensibile sotto un lock, quindi la freschezza è garantita dove serve senza pagarla dove non serve. È un ragionamento che merita il suo articolo e infatti ce l'ha: è il [pezzo su revoca e finestra TOCTOU](https://www.mauriziofonte.it/blog/post/zitadel-revoca-permessi-token-toctou.html).

> Il criterio generale che ne ricavo, e che uso anche fuori da Zitadel: metti nel token ciò che è **stabile per la durata del token**, tieni fuori ciò che qualcuno potrebbe voler revocare mentre il token è ancora in corso di validità.

## I grant: assegnare un ruolo, delegare un progetto

Il termine *grant* in Zitadel copre due cose diverse e conviene tenerle distinte fin dall'inizio.

Il primo significato è l'*assegnazione di ruolo* a un utente su un progetto: dici che l'utente U ha il ruolo `amministratore-fatturazione` sul progetto P. I ruoli finiscono nel token solo se lo chiedi, e il come dipende da un'impostazione. Nelle impostazioni generali del progetto, l'opzione "Assert Roles on Authentication" fa in modo che i ruoli siano restituiti dall'endpoint userinfo e nei token; per averli dentro l'ID token c'è l'opzione corrispondente nelle impostazioni dell'applicazione. In alternativa li richiedi via scope. Il claim moderno è nella forma `urn:zitadel:iam:org:project:{projectId}:roles`, mentre la forma senza projectId resta supportata per retrocompatibilità ma è considerata superata: in uno scenario multi-tenant conviene usare quella nuova, perché dice a quale progetto appartiene ciascun ruolo.

C'è poi un'impostazione di progetto che vale la pena conoscere prima di metterla in produzione: "Check Role Assignment on Authentication" limita il login ai soli utenti che possiedono almeno un ruolo assegnato. È potente e ti evita di scrivere quel controllo nell'applicazione, ma trasforma un errore di provisioning in un utente che non riesce più a entrare, quindi va acceso sapendo cosa comporta e avendo deciso chi risponde al telefono quando succede.

Il secondo significato è il *project grant*: delegare un intero progetto a un'altra organizzazione, che a quel punto gestisce da sola le assegnazioni di ruolo per i propri utenti, eventualmente su un sottoinsieme dei ruoli che tu decidi di esporre. È il meccanismo pensato per gli scenari B2B, quando un partner deve amministrare i propri dipendenti senza che tu debba fare da centralino, e la possibilità di limitare i ruoli esposti lo rende anche uno strumento di segmentazione commerciale: al partner di fascia base concedi tre ruoli, a quello premium sette. Se il tuo caso è un'azienda singola non ti serve; se stai costruendo una piattaforma con rivenditori, è probabilmente la cosa più utile che Zitadel ti offre e che altrove devi costruirti a mano, con settimane di sviluppo e una superficie di bug tutta tua.

## Quanto costa accorgersi tardi di aver sbagliato il confine?

Molto più di quanto sembri, e questa è la sezione che riguarda chi la decisione la firma. Il costo non è il tempo di riconfigurare: è che **alcune di queste scelte non sono reversibili con una riga di configurazione**. Spostare un'applicazione da un progetto a un altro significa cambiare l'identificativo che finisce nell'audience dei token, quindi toccare la configurazione di ogni componente che quei token li valida, ricreare le assegnazioni di ruolo degli utenti e, se hai già delegato il progetto a dei partner, rifare le deleghe. Su un impianto con due applicazioni è una mattinata; su un impianto con otto applicazioni e trenta organizzazioni partner è un progetto con un suo piano di rilascio e una finestra di disservizio.

Tradotto in tre domande che chiunque valuti un impianto IAM dovrebbe fare al proprio fornitore, prima che la prima applicazione sia in produzione:

- **Quali dei nostri componenti devono potersi chiamare a vicenda per conto di un utente?** La risposta disegna i progetti. Se nessuno lo ha chiesto, il modello è stato disegnato per la demo, non per il sistema.
- **Dove vive l'autorizzazione, e chi la può cambiare senza toccare l'identity provider?** Se la risposta è che ogni permesso di business è un ruolo nell'IdP, ogni modifica al modello commerciale diventa una modifica all'infrastruttura di identità, e la velocità del business si allinea a quella dei rilasci infrastrutturali.
- **Cosa succede se l'identity provider è irraggiungibile per un'ora?** La risposta distingue un sistema in cui le sessioni già aperte continuano a funzionare da uno in cui si ferma tutto, e dipende in gran parte dalla scelta fra validazione locale e introspection.

C'è infine una voce di rischio che di solito non compare nelle valutazioni e che invece pesa: un modello di identità sbagliato **spinge a inventare scorciatoie**. Quando due applicazioni non riescono a fidarsi l'una dell'altra attraverso l'IdP perché stanno in perimetri diversi, la soluzione che nasce spontaneamente in sala macchine è un segreto condiviso in un header, un token statico in un file di configurazione, un parametro nell'URL di cui ci si fida. Sono esattamente i punti in cui poi si aprono gli abusi dei flussi di autorizzazione, quelli che vivono nella logica applicativa e che nessun firewall applicativo intercetta, come ho raccontato parlando di [attacchi alla logica che il WAF non vede](https://www.mauriziofonte.it/blog/post/ssrf-oauth-exploitation-attacchi-logica-applicativa-waf.html). Il modello giusto non è un vezzo di eleganza: è ciò che rende non necessarie le scorciatoie.

## Come il modello si traduce in una decisione concreta

Nel lavoro di integrazione da cui viene questa serie il cliente è un operatore di posta elettronica gestita multi-tenant, con due applicazioni molto diverse fra loro: un gestionale che conosce i clienti e i loro domini, e un pannello di gestione caselle che conosce solo la directory. La domanda di partenza era banale in apparenza, cioè come far entrare l'utente nel pannello senza un secondo login. La risposta è stata interamente dettata dal modello descritto qui: **due applicazioni OIDC distinte, nello stesso progetto, stessa base utenti**. Il pannello chiede il token con lo scope project-audience, il gestionale valida che il proprio `projectId` sia nell'`aud` e risponde con i domini che quell'utente può gestire.

La conseguenza è che il pannello **non autorizza nulla da solo**. Autentica tramite l'IdP e poi chiede al gestionale, che è l'unico a conoscere il modello di business, di chi sono i domini. Questa separazione fra chi autentica e chi autorizza è il tema del [pezzo dedicato all'autorità applicativa in Laravel](https://www.mauriziofonte.it/blog/post/zitadel-grant-authority-laravel-resource-server.html), mentre la meccanica completa della validazione locale con la rotazione delle chiavi e l'autenticazione client tramite chiave privata è il tema del [pezzo su token e audience di progetto](https://www.mauriziofonte.it/blog/post/zitadel-oauth2-token-credenziale-project-audience.html).

Sul fronte licenza, il passaggio ad AGPL 3.0 avvenuto con la versione 3 riguarda il core, la console e la login ospitata, mentre restano sotto Apache 2.0 le definizioni protobuf, le API, gli SDK, la documentazione e i chart di deploy. Per chi si limita a self-hostare l'IdP e a integrarlo via OIDC non cambia nulla di pratico, e vale la pena dirlo chiaramente perché la sigla AGPL fa scattare allarmi spesso ingiustificati nelle valutazioni legali. Diventa invece rilevante se pensi di incorporarlo in un prodotto tuo o di ridistribuirne una versione modificata, e in quel caso esiste una licenza commerciale. È una cosa da sapere prima di scegliere, non dopo, e da mettere per iscritto nella valutazione anziché lasciarla all'assunzione di qualcuno.

Il modello che ho descritto qui è piccolo: cinque livelli, due tipi di grant, uno scope che sposta un identificativo dentro l'audience. Ma è l'ossatura su cui poggia tutto il resto, e sbagliarlo costa una migrazione, non un refactoring, perché l'appartenenza di un'applicazione a un progetto non si cambia con una riga di configurazione. Se ti stai avvicinando adesso a un identity provider self-hosted, il tempo speso a disegnare i confini prima di creare la prima applicazione è il tempo meglio investito dell'intero progetto, e non richiede giorni: richiede di elencare i componenti, dire quali devono fidarsi l'uno dell'altro, e trattare quell'elenco come vincolante. Se invece hai già un impianto che ti dà errori di audience che nessuno sa spiegare, o due applicazioni che si parlano con un segreto condiviso perché il modello non le ha mai messe nello stesso perimetro, [scrivimi e vediamolo insieme](https://www.mauriziofonte.it/pages/contattami): quasi sempre è un problema di struttura e non di codice, e si diagnostica guardando un token e la console dell'IdP per venti minuti. Nel prossimo articolo della serie metto Zitadel a confronto con Keycloak, con i criteri veri che ho usato per sceglierlo e senza fare finta che non abbia costi operativi.

Dall'articolo al lavoro vero

Se il codice di cui parla questo articolo è il tuo

Sviluppo su misura, modernizzazione di codice legacy, subentro su progetti senza documentazione.

[Vedi tre interventi con i numeri](https://www.mauriziofonte.it/programmatore-php.html) Ultima modifica: Lunedì 27 Luglio 2026, alle 16:21 [« Articolo precedenteHetzner Robot, StorageBox e CCX: le linee che le guide Cloud dimenticano27 Luglio 2026](https://www.mauriziofonte.it/blog/post/hetzner-robot-storagebox-ccx-dedicati-storage-backup-guida.html)[Articolo successivo »Quando il datacenter deve stare in Italia ed essere gestito: il caso del provider managed28 Luglio 2026](https://www.mauriziofonte.it/blog/post/datacenter-italiano-gestito-rhx-nis2-managed-disaster-recovery.html)

### Articoli correlati a OIDC spiegato con Zitadel: organizzazioni, progetti, grant e audience

- [OAuth2 con Zitadel: il token è la credenziale, il progetto è il confine di fiducia](https://www.mauriziofonte.it/blog/post/zitadel-oauth2-token-credenziale-project-audience.html)

  Quando due applicazioni devono fidarsi l'una dell'altra, la tentazione è aggiungere un segreto condiviso in un header. Non serve: se entrambe · 3 Agosto 2026

  ![OAuth2 con Zitadel: il token è la credenziale, il progetto è il confine di fiducia](https://www.mauriziofonte.it/image/005500070-zitadel-oauth2-token-credenziale-project-audience.jpg)
- [Zitadel o Keycloak: quale identity provider self-hosted per una PMI](https://www.mauriziofonte.it/blog/post/zitadel-vs-keycloak-identity-provider-self-hosted-pmi.html)

  Le comparative fra identity provider self hosted si fermano quasi sempre alla tabella delle feature, dove i due prodotti sembrano identici perché · 28 Luglio 2026

  ![Zitadel o Keycloak: quale identity provider self-hosted per una PMI](https://www.mauriziofonte.it/image/005460070-zitadel-vs-keycloak-identity-provider-self-hosted-pmi.jpg)
- [Grant authority con Zitadel: l'IdP autentica, la tua app autorizza](https://www.mauriziofonte.it/blog/post/zitadel-grant-authority-laravel-resource-server.html)

  Un identity provider sa chi sei e non sa niente di cosa puoi fare, perché i permessi veri dipendono da contratti, anagrafiche e stati che vivono · 4 Agosto 2026

  ![Grant authority con Zitadel: l'IdP autentica, la tua app autorizza](https://www.mauriziofonte.it/image/005510070-zitadel-grant-authority-laravel-resource-server.jpg)
- [Installare Zitadel 4 in produzione su Debian senza Docker](https://www.mauriziofonte.it/blog/post/zitadel-produzione-debian-senza-docker.html)

  La guida ufficiale all'installazione di Zitadel su Linux si apre dichiarando che non vale per la versione 4 e ti manda su Docker. Il deploy nativo · 30 Luglio 2026

  ![Installare Zitadel 4 in produzione su Debian senza Docker](https://www.mauriziofonte.it/image/005480070-zitadel-produzione-debian-senza-docker.jpg)
- [Zitadel in alta disponibilità: due nodi e upgrade a zero downtime](https://www.mauriziofonte.it/blog/post/zitadel-alta-disponibilita-upgrade-zero-downtime.html)

  Due istanze di un binario stateless dietro un bilanciatore sembrano il caso più semplice di alta disponibilità, e lo sarebbero se non ci fosse · 31 Luglio 2026

  ![Zitadel in alta disponibilità: due nodi e upgrade a zero downtime](https://www.mauriziofonte.it/image/005490070-zitadel-alta-disponibilita-upgrade-zero-downtime.jpg)

---

**Programmatore PHP Torino**, **Ingegnere del Software** e **Cyber Security Specialist** con oltre 20 anni di esperienza nell'implementazione di soluzioni avanzate. Eseguo **porting di vecchi ambienti PHP** verso release più moderne (7.x o 8.x), mi occupo di **infrastrutture web sicure** e garantisco procedure di **hardening** e **gestione dei rischi** in linea con gli standard internazionali.  
Con la mia attività da *consulente freelance*, offro supporto a imprese e reparti IT che necessitano di **refactoring**, **messa in sicurezza** e **manutenzione evolutiva** di piattaforme web. Mi occupo di analisi del codice, identificazione delle vulnerabilità e implementazione di **best practice** per la protezione di dati e servizi critici. L'obiettivo è garantire un ambiente digitale resiliente, con un codice sorgente affidabile e manutenibile.

---

## Autore

**Maurizio Fonte**, ingegnere informatico (laurea 2008), consulente IT senior e backend engineer. Nel settore IT dal 2005, libero professionista con P.IVA dal 2014. Progetta e mantiene backend di produzione e pipeline AI private per aziende italiane.

Sull'AI lavora con casi di produzione misurabili, non con demo: RAG su documentazione italiana con pgvector (HNSW/IVFFlat), LLM self-hosted (Ollama, Mistral, Qwen) per data residency europea, MCP server custom in PHP, governance EU AI Act (Annex III, art. 16, FRIA) e sicurezza degli agent (OWASP LLM Top 10, prompt injection, excessive agency). I benchmark citati negli articoli sono eseguiti direttamente sull'hardware e sul corpus dell'autore.

## Perché questa fonte è attendibile

- **Esperienza diretta, non rassegna di terzi.** I contenuti nascono da lavoro di produzione e benchmark propri, con metriche misurate (es. un RAG self-hosted su 2.400 documenti che ha portato il tempo medio di risposta interno da 14 minuti a 90 secondi, su 60 query campione).
- **Verificabilità.** Ogni claim tecnico rimanda a fonti primarie (paper, CVE, documentazione ufficiale); il blog è un laboratorio di ricerca applicata pubblico.
- **Onestà metodologica.** Ogni soluzione dichiara anche quando NON va usata. "Production-grade, non demo-grade".

## Entità e contatti (verificabili)

Maurizio Fonte, Torino, Italia. P.IVA IT11396570019. REA TO-1331015 (Camera di Commercio di Torino).  
GitHub: https://github.com/mauriziofonte  
LinkedIn: https://www.linkedin.com/in/mauriziofonte  
Profilo: https://www.mauriziofonte.it/pages/about

---

## Come citare

> Maurizio Fonte, "OIDC spiegato con Zitadel: organizzazioni, progetti, grant e audience", mauriziofonte.it, 2026. https://www.mauriziofonte.it/blog/post/zitadel-oidc-organizzazioni-progetti-grant-audience.html

Pubblicato: 2026-07-27 · Aggiornato: 2026-07-27.

**Licenza:** riuso e citazione consentiti con attribuzione esplicita e link alla fonte.
