
# Endpoint OAuth 2.0 e OpenID Connect

> **Stato: `planned`.** Questa pagina descrive la superficie del protocollo di ogni ambiente KeenAuth così come specificata nel piano (§13). Gli endpoint sono in fase di sviluppo nella fase 2 e non sono ancora disponibili in un ambiente ospitato. I dettagli possono ancora cambiare prima della disponibilità generale.

Ogni ambiente è un proprio server di autorizzazione OAuth 2.0 e un provider OpenID Connect. Gli endpoint non fanno parte dell'API di gestione: si trovano sull'host dell'ambiente, `https://<environment-slug>.<region>.keenauth.app`, oppure sul tuo dominio personalizzato verificato. Nella tabella, `<issuer>` è l'issuer dell'ambiente, cioè il valore di `issuer` nel documento di discovery.

## Endpoint

| Endpoint | Metodo e percorso | Autenticazione del client |
|---|---|---|
| Discovery | `GET <issuer>/.well-known/openid-configuration` e `GET <issuer>/.well-known/oauth-authorization-server` (RFC 8414, stesso contenuto) | Nessuna |
| Chiavi | `GET <issuer>/.well-known/jwks.json` | Nessuna |
| Autorizzazione | `GET` oppure `POST <login host>/oauth2/authorize` | Nessuna (browser) |
| Richiesta di autorizzazione pushed (RFC 9126) | `POST <issuer>/oauth2/par` | Richiesta per i client confidenziali; `client_id` per i client pubblici |
| Token | `POST <issuer>/oauth2/token` | Richiesta per i client confidenziali; `client_id` per i client pubblici (DPoP è facoltativo) |
| Autorizzazione del dispositivo (RFC 8628) | `POST <issuer>/oauth2/device_authorization` | Come l'endpoint del token |
| Revoca (RFC 7009) | `POST <issuer>/oauth2/revoke` | Come l'endpoint del token |
| Introspezione (RFC 7662) | `POST <issuer>/oauth2/introspect` | Solo client confidenziali |
| UserInfo | `GET` oppure `POST <issuer>/oauth2/userinfo` | Access token Bearer o DPoP |
| Fine sessione | `GET` oppure `POST <login host>/oauth2/logout` | Nessuna (`id_token_hint` oppure `client_id`) |

`<login host>` è qualsiasi dominio di accesso dell'ambiente: l'host predefinito oppure un dominio personalizzato aggiunto. Il documento di discovery viene servito solo sull'host dell'issuer. Su un altro host di accesso, `/.well-known/openid-configuration` restituisce `404` con l'URL dell'issuer nel corpo.

## Tipi di grant

| Grant | Uso |
|---|---|
| `authorization_code` | Accesso da browser e app native. PKCE con `S256` è obbligatorio. |
| `refresh_token` | Rinnova i token. Ogni utilizzo ruota il refresh token, e riutilizzarne uno vecchio revoca l'intera famiglia di token. |
| `client_credentials` | Accesso da macchina a macchina. |
| `urn:ietf:params:oauth:grant-type:device_code` | Dispositivi senza tastiera, come una TV o uno strumento da riga di comando. |
| `urn:ietf:params:oauth:grant-type:token-exchange` | Delega e impersonificazione tra servizi. |

I flussi implicit (`response_type=token` e qualsiasi cosa che contenga `id_token`), il grant con credenziali della resource owner (password) e i response type ibridi non sono supportati, né ora né in seguito. La RFC 9700 vieta i primi due.

## Autorizzazione del dispositivo

Un dispositivo senza browser avvia il flusso con `POST <issuer>/oauth2/device_authorization`. Possono usarlo solo le applicazioni di tipo `device` o `native` che elencano esplicitamente il grant del dispositivo. La risposta contiene un `device_code`, uno `user_code` e un indirizzo di verifica. L'utente apre l'indirizzo su un altro dispositivo, accede e approva. Nel frattempo, il dispositivo interroga l'endpoint del token con `grant_type=urn:ietf:params:oauth:grant-type:device_code`. Lo `user_code` ha 8 caratteri ed è mostrato come `XXXX-XXXX`. Un device code è valido per 10 minuti e funziona una sola volta. Il dispositivo interroga al massimo ogni 5 secondi; un polling più frequente riceve la risposta `slow_down`, che aggiunge 5 secondi all'intervallo. Il `verification_uri` è `https://<login host>/u/device`, e all'utente vengono mostrati l'applicazione, gli scope richiesti e il paese del dispositivo che ha avviato la richiesta, prima di approvare.

## Regole di sicurezza

L'ambiente segue senza eccezioni la Security Best Current Practice di OAuth 2.0 (RFC 9700):

- Il redirect URI deve corrispondere byte per byte a uno registrato. Non ci sono wildcard.
- PKCE accetta solo `S256`; `plain` viene sempre rifiutato. PKCE è obbligatorio per i client pubblici ed è attivo di default per ogni applicazione. Un'applicazione `web` confidenziale può disattivarlo nelle sue impostazioni, e solo se in quel caso l'ambiente richiede ancora `nonce`.
- Gli SDK ufficiali inviano uno `state` a 128 bit e un `nonce` e verificano entrambi al ritorno.
- Un authorization code è valido per 60 secondi e funziona una sola volta. Presentare un codice già usato restituisce `invalid_grant` e revoca i refresh token e l'access token prodotti dal primo utilizzo.
- Le richieste di autorizzazione pushed mantengono i parametri della richiesta fuori dalla barra degli indirizzi del browser. Sono disponibili in ogni piano, e l'impostazione `require_par` le rende obbligatorie per un'applicazione o per l'intero ambiente.
- I refresh token ruotano a ogni utilizzo, e il rilevamento del riutilizzo revoca la famiglia.
- DPoP (RFC 9449) lega un access token a una chiave detenuta dal client. Per verificare i token vincolati nella tua API, consulta [Verifica dei token nella tua API](/docs/sdk/token-verification).

## Sessioni e disconnessione

Dopo un accesso riuscito, l'ambiente mantiene una sola sessione Single Sign-On in un cookie `HttpOnly` sull'host di accesso. Le applicazioni dello stesso ambiente la riutilizzano, quindi una seconda applicazione non chiede di nuovo la password, a meno che la sua policy non richieda un'autenticazione più forte o più recente. Il tuo codice non vede mai il cookie: vede solo la risposta di autorizzazione.

L'endpoint di fine sessione (OpenID Connect RP-Initiated Logout 1.0) termina quella sessione, revoca i refresh token che le appartengono e notifica le applicazioni che hanno registrato un indirizzo di back-channel logout. Per elencare o revocare le sessioni di un utente dal tuo backend, usa gli [endpoint delle sessioni dell'API di gestione](/docs/api/management/users/list-sessions).

Se l'utente ha effettuato l'accesso tramite una connessione aziendale, aggiungi `federated=true` alla richiesta di fine sessione per disconnetterlo anche presso il suo provider di identità. La sessione qui termina per prima; il browser poi va al logout del provider di identità (SAML single logout, oppure l'endpoint di fine sessione del provider OpenID) e torna a `post_logout_redirect_uri`. Questo avviene solo se per la connessione è attivo il logout presso il provider di identità e il provider pubblica un indirizzo di logout. Altrimenti, oppure se il provider non è raggiungibile, la richiesta funziona come senza il parametro. La disconnessione presso il provider di identità può anche terminare le altre applicazioni dell'utente che lo usano.
