# Registry 401, 402, 403: tokens, plans and permissions without guessing

Three codes, three causes: 401 is identity, 402 is payment, 403 is the right to access. Start the diagnosis from the command line, not from the browser.

> Page: https://ui.eneawork.it/blog/registry-401-402-403-token-piani
> Markdown: https://ui.eneawork.it/blog/registry-401-402-403-token-piani.md

*2026-11-01*

Risposta breve: 401 significa identità mancante o non valida, 402 significa pagamento richiesto, 403 significa identità valida ma senza diritto sulla risorsa. Diagnostica con curl prima di toccare la configurazione.

I registry privati sono il caso in cui una risposta HTTP diventa un blocco di lavoro. Nel catalogo EneUI ci sono 1.472 librerie indicizzate e 1.556 blocchi con preview al 1 novembre 2026: la licenza è la prima cosa da leggere, prima del token. Il catalogo EneUI ha misurato 111.985 componenti, 1.556 blocchi, 12.808 icone da 1.472 librerie, letti da /api/stats il 1 novembre 2026. Ogni comando qui sotto è eseguibile in locale: nessun passaggio richiede un account.

## La tabella dei codici

## Il meccanismo: l'ordine in cui il registry risponde

Un registry privato controlla tre cose in sequenza: chi sei, se hai pagato, cosa puoi leggere. Il primo controllo produce 401 quando l'header manca, è malformato o è scaduto. Il secondo produce 402 quando l'identità è valida e l'entitlement no. Il terzo produce 403 quando l'identità è valida, il piano esiste e lo scope o il namespace non coprono quella risorsa. L'ordine conta: un token scaduto su una risorsa a pagamento restituisce 401, non 402, quindi il codice da solo non racconta tutto. Il CLI stampa lo status e scarta il corpo, che è dove il registry scrive la ragione.

## Un passo diagnostico: leggi il corpo, non solo il codice

Il comando qui sotto stampa in una riga lo status, l'header WWW-Authenticate e i primi caratteri del corpo: il primo parla del gateway, l'ultimo del registry. Se la variabile è vuota, l'header parte senza token e il 401 è già spiegato. Se WWW-Authenticate manca, la risposta non viene dal servizio ma da un proxy davanti. Se il corpo nomina uno scope, il token è buono e il permesso no.

node -e "fetch('https://registry.acme.dev/r/button.json',{ headers:{Authorization:'Bearer '+process.env.ACME_REGISTRY_TOKEN} }).then(async r=>console.log( r.status, r.headers.get('www-authenticate'), (await r.text()).slice(0,120)))"

## Configurazione corretta

// components.json { "registries": { "@acme": { "url": "https://registry.acme.dev/r/{name}.json", "headers": { "Authorization": "Bearer ${ACME_REGISTRY_TOKEN}" } } } }

Il token sta in una variabile d'ambiente, non nel file. Se il file è già stato committato con il token in chiaro, ruotalo: rimuoverlo dalla storia non annulla la copia che qualcuno ha già scaricato.

## Verifica senza installare

curl -i -H "Authorization: Bearer $ACME_REGISTRY_TOKEN" \ https://registry.acme.dev/r/button.json

Il codice di stato risponde alle tre domande in un colpo: se è 200 il problema è nella configurazione del client; se è 401 il token non arriva; se è 403 il token è riconosciuto e manca il permesso.

## Quando la correzione non funziona

Se curl funziona e il client no, la variabile non arriva al processo. Succede in CI senza secret, in container senza env_file, o in un comando eseguito da un contesto che non eredita l'ambiente. Verifica con node -p process.env.ACME_REGISTRY_TOKEN nello stesso contesto. Un secondo caso è un proxy che rimuove l'header Authorization: in quel caso il 401 arriva dal gateway, non dal registry.

## Quando la correzione comune peggiora le cose

Davanti a un 401 la reazione è rigenerare il token. Se il 401 veniva da un proxy che rimuove Authorization, il token nuovo non cambia nulla e ora hai due variabili: un secret ruotato e un header ancora tagliato. Ruotare senza aver isolato il livello rende il problema più difficile da leggere, perché il vecchio token funzionava in curl e il nuovo no. Isola prima: stesso comando, stessa variabile, dal contesto in cui gira il client. Se curl passa e il client no, il token è sano e il problema è il trasporto.

## Un limite con un nome: due 401 identici

Il codice 401 non distingue «token mai arrivato» da «token arrivato e rifiutato»: entrambi sono 401, e un gateway può generarne uno suo prima che la richiesta tocchi il registry. Il limite si chiama indistinguibilità del 401; si riduce con header aggiuntivi, un WWW-Authenticate che porta il motivo, un X-Registry-Request-Id da correlare nei log, oppure dando al gateway e al servizio due codici diversi: scelta che molti registry non fanno.

## Come prevenirlo

Il test in CI vale più di una checklist perché vede il registry reale. Aggiungi un secondo controllo sul 402: un endpoint che risponde 402 senza un alert è un cliente che scopre il problema al momento dell'installazione, non prima.

## Dove continuare

Nel catalogo: componenti, blocco pricing, icone e classifica dei cataloghi. Le guide: registry privati, token e namespace e temi gratuiti e premium; il confronto: 1.556 blocchi con preview.

## FAQ

### 401 e 403 non sono la stessa cosa?

No. Il 401 dice che non sai chi sei; il 403 dice che sai chi sei ma non puoi accedere a quella risorsa. Le correzioni sono diverse.

### Dove metto il token?

In una variabile d'ambiente letta da `components.json`, mai in chiaro nel file committato. In CI la variabile arriva dal secret store.

### Come verifico il token senza installare nulla?

Con `curl -i -H "Authorization: Bearer $TOKEN" `. Il codice di stato ti dice se il problema è il token o la risorsa.

### Il 402 può arrivare anche con un token valido?

Sì: significa che l'identità è riconosciuta ma il piano non include quella risorsa. Serve un acquisto o un upgrade, non un altro token.

### Posso usare registry pubblici senza header?

Sì, se il registry non richiede autenticazione. La configurazione dei namespace resta utile per l'ordine di risoluzione.
