Tema
OAuth2 per i connettori
Non è un connettore: è l'identità che IMAP e SMTP usano per autenticarsi dove la password non basta più — Gmail, Google Workspace, Microsoft 365. Lo usa anche il connettore Zoho CRM, che autentica ogni richiesta alla Records API con il token che questa identità rinnova. Procedura passo passo nel runbook oauth-google-posta.md.
Perché esiste
I connettori sapevano già parlare XOAUTH2, ma un access token vive un'ora: incollarne uno in IMAP_ACCESS_TOKEN è una configurazione che funziona per un'ora e poi torna rossa. Questo modulo tiene il refresh token e scambia un access token nuovo quando serve.
Un'identità, due connettori
La stessa casella Google si legge e si scrive con lo stesso consenso, quindi l'identità sta in un registry suo e IMAP e SMTP la referenziano per id. Duplicare CLIENT_SECRET e REFRESH_TOKEN nei due blocchi significherebbe, prima o poi, ruotarne uno solo.
Variabili
| Variabile | Default | Note |
|---|---|---|
OAUTH_CLIENT_ID | — | obbligatoria se il registry è usato |
OAUTH_CLIENT_SECRET | — | obbligatoria |
OAUTH_REFRESH_TOKEN | — | obbligatoria; ottenuto una volta sola, vedi runbook |
OAUTH_TOKEN_ENDPOINT | https://oauth2.googleapis.com/token | deve essere https://; Microsoft 365 si configura qui |
OAUTH_SCOPE | — | solo se il provider lo vuole al refresh; Google no |
OAUTH_INSTANCES | — | più caselle: ordini,notifiche → OAUTH_<ID>_* |
Chi le usa:
| Variabile | Default | Note |
|---|---|---|
IMAP_AUTH=oauth2 | dedotto | e IMAP_PASSWORD va tolta |
IMAP_OAUTH_INSTANCE | default | quale identità rinnova il token di quella casella |
SMTP_AUTH=oauth2 | dedotto | e SMTP_PASSWORD va tolta |
SMTP_OAUTH_INSTANCE | default | di norma la stessa di IMAP |
ZOHO_<ID>_OAUTH_INSTANCE | default | l'identità di un'organizzazione Zoho CRM, con il token endpoint di Zoho |
Zoho risponde 200 anche a un refresh rifiutato, con { "error": … } nel corpo: il fornitore lo tratta come un rifiuto, un ConfigError con il codice di Zoho (per esempio invalid_code).
Le variabili sono dichiarate in MANIFEST_OAUTH: un'identità incompleta dà un ConfigError che elenca tutte le variabili mancanti.
Nel piano
Un'identità OAuth2 non è un nodo. Nel piano compare nella riga credenziale delle caselle IMAP e dei server SMTP che la usano: OAuth · identità default · impostata, oppure … · mancano OAUTH_CLIENT_SECRET, OAUTH_REFRESH_TOKEN con origine mancante e la variabile che punta alla prima da impostare. Un'identità che non è in OAUTH_INSTANCES la run non la trova, anche se le sue variabili ci sono: il piano lo dice con · manca OAUTH_INSTANCES. Il piano la risolve con risolviIdentitaOauth(id, env), che non lancia e dei segreti restituisce solo lo stato.
Per etl env check, identitaOauthDichiarate(caselle, env) dà le sole identità che le caselle date usano davvero, cioè quelle su <PREFIX>AUTH=oauth2 senza <PREFIX>ACCESS_TOKEN, da aggiungere alle istanze di ambienteDellaPipeline: una pipeline con caselle su password non chiede variabili OAUTH_*.
Il registry può essere vuoto
È l'unico, ed è deliberato. Un PG_HOST mancante è una configurazione rotta; OAuth2 invece è una scelta, e la maggioranza delle installazioni continuerà con una password. Senza OAUTH_INSTANCES né OAUTH_CLIENT_ID il registry esce vuoto e i connettori non cambiano comportamento.
La tolleranza finisce lì. Un'istanza dichiarata in OAUTH_INSTANCES e incompleta è un errore, e un IMAP_OAUTH_INSTANCE che nomina un id inesistente pure: ricadere in silenzio sul token statico significherebbe autenticarsi con una credenziale diversa da quella che si crede.
Come si usa dal codice
ts
const oauth = fornitoriOauth(loadOauthRegistry(env));
const tokenImap = oauth(imap.auth, imap.oauthInstance);
imapSource(imap, {
// …
...(tokenImap !== undefined ? { client: { accessToken: tokenImap } } : {}),
});Un risolutore per run, non per nodo. fornitoriOauth memoizza per id d'istanza: i nodi che condividono l'identità condividono la cache del token. Una pipeline di posta può toccare la stessa casella in tre punti — sorgente, sessione delle action IMAP, notifiche SMTP — e senza la memoizzazione la stessa run chiederebbe tre token invece di uno. Il guaio non è lo spreco: è che funzionerebbe, quindi nessuno se ne accorgerebbe fino al primo rate limit.
Il fornitore serializza anche le richieste: due nodi che chiedono il token insieme sulla cache fredda fanno una chiamata sola.
Come tratta le credenziali
- Niente redirect. La
fetchverso il token endpoint usaredirect: "error". Il default difetchè seguirli, e su un307il body — client secret e refresh token — viene ripetuto verso l'host nuovo, anche inhttp://. Il vincolohttps://guarda solo il primo URL: da solo non basterebbe. - Niente credenziali nei messaggi d'errore. Il testo che arriva dal provider viene redatto (client secret e refresh token sostituiti) e troncato a 160 caratteri: più d'un IdP rieccheggia il valore rifiutato, e la CLI stampa gli errori su stderr.
- Nessuna
cause, come in IMAP e SMTP:console.errorsegue la catena delle cause per intero. - Timeout di 30 secondi, come gli altri connettori: un endpoint muto non blocca la run.
- La cache del token vive in memoria, per la durata della run. Mai su disco.
Errori
| Messaggio | Che cosa vuol dire |
|---|---|
OAuth2: refresh token rifiutato (invalid_grant) | Non più valido. Su un progetto Internal la causa prima è il cambio password della casella: lo scope è un ambito Gmail. Le altre cause sono nel runbook |
OAuth2: il provider ha rifiutato la richiesta (invalid_client…) | Client ID o secret sbagliati |
OAuth2: il token endpoint non risponde | Rete, DNS, timeout, o un redirect rifiutato |
OAuth2: risposta del provider senza access_token utilizzabile | Il provider ha risposto 200 con un corpo che non contiene un token |
Identità OAuth2 "…" non configurata | IMAP_OAUTH_INSTANCE o SMTP_OAUTH_INSTANCE nomina un id che non esiste |

