> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Chiavi di firma (JWKS) | Didit Authentication API

> Didit: GET /.well-known/jwks.json restituisce le chiavi pubbliche ES256. Cache per kid; rotazione ogni 30 giorni con sovrapposizione di un giorno.

> [!WARNING]
>
> L'autenticazione è una novità. Questi endpoint sono esposti dall'emittente della tua applicazione, come `https://<name>.auth.didit.me`, e non accettano mai la tua chiave API di Didit.

Le chiavi vengono ruotate ogni 30 giorni, con un giorno di sovrapposizione su ciascun lato, quindi un JWKS memorizzato nella cache per 5 minuti continua a consentire la verifica dei token durante una rotazione. Richiedilo di nuovo quando un token indica un `kid` che non hai, al massimo una volta al minuto. Vedi [Cache e rotazione](https://docs.didit.me/it/authentication/tokens-and-jwks.md#cache-e-rotazione).


## OpenAPI

````yaml it/openapi-authentication.json GET /.well-known/jwks.json
openapi: 3.0.3
info:
  title: Didit Authentication API
  version: 1.0.0
  description: >-
    Gli endpoint lato server di Didit Authentication, il prodotto di accesso per
    gli utenti finali della tua applicazione. Authentication è una funzionalità
    **nuova** e raggiungerà l'ambiente di produzione nella release 2026-11-01.


    ## URL di base


    Ogni applicazione è un proprio emittente OpenID Connect e ogni endpoint
    indicato di seguito è servito alla radice di tale emittente:


    - `https://<name>.auth.didit.me` per un'applicazione di produzione, o
    `https://<name>.sandbox.auth.didit.me` per un'applicazione sandbox.

    - Il tuo dominio personalizzato, una volta attivo. Quest'ultimo sostituisce
    quindi l'host predefinito come emittente: i nuovi token lo indicano in
    `iss`, la discovery punta ad esso e la chiave pubblicabile cambia. I token
    di accesso emessi sotto l'host predefinito falliscono su `/session/`,
    `/step-up/` e `/monitoring-token/` fino al loro rinnovo.


    L'ambiente di produzione e la sandbox sono applicazioni separate, quindi
    sono emittenti separati con chiavi separate. La chiave pubblicabile è
    `pk_live_` (produzione) o `pk_test_` (sandbox) seguita dalla codifica
    base64url senza padding dell'emittente, senza barra finale: decodificala per
    trovare l'emittente. Si tratta di un identificatore pubblico, non di una
    credenziale.


    Gli stessi endpoint JSON sono serviti anche sotto
    `https://apx.didit.me/auth/v2/authentication/{application_id}/`. I token
    indicano sempre l'emittente sopra descritto, indipendentemente
    dall'indirizzo che li ha emessi.


    ## Credenziali


    Questi endpoint non richiedono mai la tua chiave API Didit o un token della
    console.


    - La discovery, il JWKS e `POST /token/` non richiedono credenziali. I
    client sono pubblici: non esiste alcun segreto client e il codice di
    autorizzazione è associato al relativo verificatore PKCE (`S256`).
    `client_id` è l'ID della tua applicazione.

    - `/session/`, `/step-up/` e `/monitoring-token/` richiedono il token di
    accesso della persona: `Authorization: Bearer <access_token>`. Ogni chiamata
    riuscita conta come attività sulla sessione, quindi azzera e riavvia il
    timeout di inattività della sessione.


    ## Body della richiesta


    Ogni endpoint che accetta un body supporta formati JSON, form-encoded e
    multipart. Questo documento elenca JSON, oltre al formato form-encoded per
    `POST /token/` come inviato dai client OAuth. Un campo non accettato
    dall'endpoint restituisce `400 {"<field>": "unknown_field"}`.


    ## Token


    - **Token di accesso**: un JWT ES256 con intestazione `typ: at+jwt`, valido
    per un massimo di 5 minuti e mai più a lungo della relativa sessione. Claim:
    `AccessTokenClaims`.

    - **ID token**: un JWT ES256 con intestazione `typ: JWT`. Claim:
    `IDTokenClaims`. Non viene mai accettato come token di accesso.

    - **Refresh token**: una stringa casuale che ruota a ogni utilizzo. L'invio
    di un refresh token già utilizzato revoca la sessione.


    Verifica un token con le chiavi restituite da `GET /.well-known/jwks.json`:
    l'algoritmo deve essere `ES256`, `typ` deve corrispondere al tipo di token,
    `iss` deve coincidere con l'emittente configurato e `aud` con l'ID della tua
    applicazione. La verifica offline rileva una sessione revocata solo dopo la
    scadenza del relativo token di accesso; `GET /session/` è il controllo
    istantaneo.


    ## Errori


    | Body | Quando |

    | --- | --- |

    | `{"error": "<code>"}` | Errori restituiti da `POST /token/`, tutti con
    stato `400`, nella struttura del body definita dalla sezione 5.2 della [RFC
    6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2): `invalid_grant`,
    `invalid_client` e l'errore `mfa_required` di Didit. Errori del servizio:
    `temporarily_unavailable`, `monitoring_unavailable`, `monitoring_disabled`.
    |

    | `{"<field>": ["<message>"]}` o `{"<field>": "<code>"}` | La convalida di
    un campo della richiesta non è riuscita. `non_field_errors` indica una
    regola applicata su più campi e `unknown_field` un campo non accettato
    dall'endpoint. |

    | `{"detail": "<message>"}` | `401` (`invalid_token`), `403`
    (`origin_not_allowed`), `404` (applicazione o step-up sconosciuto) e `429`
    (limite di frequenza). Anche `400` per un body che non può essere analizzato
    (`JSON parse error - ...`), `405` per un metodo non gestito dall'endpoint e
    `415` per un `Content-Type` non supportato. |


    Uno stato `401` include inoltre l'intestazione `WWW-Authenticate: Bearer`,
    mentre un `429` include `Retry-After` in secondi.


    Due tipi di rifiuto non restituiscono JSON. Un indirizzo che non corrisponde
    a un emittente viene rifiutato prima di raggiungere questi endpoint, ad
    esempio con un `404` vuoto per un nome `*.auth.didit.me` non utilizzato. Un
    parametro `step_up_id` che non è un UUID restituisce una pagina `404`.


    ## Limiti di frequenza


    Una richiesta deve superare due livelli.


    **Limiti dell'endpoint**, conteggiati per indirizzo IP del client, per
    applicazione e per endpoint:


    - Discovery e JWKS: 1.200 richieste al minuto e 12.000 all'ora.

    - Tutti gli altri endpoint: 30 richieste al minuto e 300 all'ora. `GET` e
    `DELETE /session/` condividono un unico conteggio.


    Al superamento di un limite: `429 {"detail": "Too many requests from this IP
    address. Please wait before trying again. Expected available in 60
    seconds."}`, oppure `3600 seconds` per il limite orario.


    **Protezione bot**, attiva su ogni `POST` e `DELETE`. I suoi bucket sono
    condivisi da tutte le richieste `POST` e `DELETE` dell'applicazione, inclusi
    i passaggi di accesso ospitati, e si ricaricano continuamente:


    - 60 richieste al minuto per indirizzo IP del client.

    - 30 richieste al minuto per dispositivo, per le richieste che identificano
    il dispositivo, come fanno gli SDK per browser e nativi.

    - 3.000 richieste al minuto per l'intera applicazione, considerando tutti
    gli indirizzi IP. I rinnovi dei token (`POST /token/` con
    `grant_type=refresh_token`) attingono invece a un bucket dedicato: 6.000 al
    minuto per l'intera applicazione.


    Al superamento di un bucket: `429 {"detail": "rate_limited Expected
    available in N seconds."}` (`1 second.` quando N è 1). Il bucket per IP si
    applica a diversi endpoint, quindi un singolo indirizzo che combina chiamate
    di token, step-up e disconnessione può esaurirlo prima di raggiungere il
    limite del singolo endpoint. Il bucket dell'applicazione conteggia ogni
    client dell'applicazione, inclusi i browser.


    Entrambi i livelli rispondono prima che l'endpoint venga eseguito, quindi
    una richiesta che ha ricevuto un codice `429` non è stata elaborata:
    effettua un nuovo tentativo dopo il tempo indicato in `Retry-After`, rinnovo
    incluso.


    ## Richieste del browser


    Una richiesta contenente un'intestazione `Origin` deve provenire da una
    delle origini dell'applicazione o dalle sue origini consentite, altrimenti
    riceve `403 origin_not_allowed`. Le richieste da server a server non inviano
    alcun `Origin`.


    ## Non trattati in questa sezione


    Questi percorsi servono le pagine ospitate, gli SDK nativi e per browser e
    gli agenti IA. Non fanno parte del contratto server e gli SDK server non li
    chiamano:


    - Passaggi di accesso: `POST /authorize/`, `POST /password/`, `/email/*`,
    `/phone/*`, `/password-reset/*`, `/passkeys/*`, `/mfa/*`, `/social/*` e
    `/protection/complete/`.

    - Pagine ospitate e callback: `/sign-in`, `/magic`, `/invite`, `/reset`,
    `/verify/`, `/sso/*`, `/wallet/callback/`, `/logo/` e i file di associazione
    delle app native sotto `/.well-known/`.

    - Accesso agenti: `/agents/*` e `/grants/`, compreso `GET /agents/session/`,
    il controllo in tempo reale del token di accesso di un agente IA. L'accesso
    degli agenti non fa parte di questa versione del contratto.

    - L'API di gestione della console per Authentication, che accetta sessioni
    della console.


    Gli eventi di Authentication non vengono ancora inviati come webhook,
    pertanto questo documento non definisce alcun webhook.
servers:
  - url: https://{issuer}
    description: 'L''emittente (issuer) della tua applicazione: la sua origine di accesso.'
    variables:
      issuer:
        default: your-app.auth.didit.me
        description: >-
          L'host dell'emittente: `<name>.auth.didit.me` (produzione),
          `<name>.sandbox.auth.didit.me` (sandbox) o il tuo dominio
          personalizzato attivo.
security: []
tags:
  - name: Issuer
    description: Chiavi di discovery e di firma, per verificare i token.
  - name: Tokens
    description: I grant di tipo authorization code e refresh.
  - name: Sessions
    description: Verifica e termina la sessione associata a un token di accesso.
  - name: Step-ups
    description: Verifica prima di un'azione sensibile.
  - name: Monitoring
    description: >-
      Credenziali del dispositivo per gli eventi di monitoraggio delle
      transazioni.
paths:
  /.well-known/jwks.json:
    get:
      tags:
        - Issuer
      summary: Recupera le chiavi di firma
      description: >-
        Le chiavi pubbliche ES256 dell'applicazione. Ogni token indica la
        propria chiave nell'intestazione `kid`.


        Le chiavi vengono ruotate ogni 30 giorni. La chiave successiva viene
        pubblicata un giorno prima di iniziare a firmare, e la chiave precedente
        rimane pubblicata per un giorno dopo aver smesso, in modo che un JWKS
        memorizzato nella cache per un massimo di 5 minuti continui a consentire
        la verifica durante una rotazione. Memorizza le chiavi nella cache in
        base al `kid` e recupera nuovamente il JWKS quando un token indica un
        `kid` che non possiedi, al massimo una volta al minuto. Quando Didit
        revoca una chiave compromessa, la chiave viene rimossa immediatamente da
        questo documento e `GET /session/` rifiuta ogni token firmato da essa.
        Una chiave sostitutiva inizia a firmare immediatamente, senza il giorno
        di pubblicazione anticipata, quindi un JWKS memorizzato nella cache fino
        a 5 minuti prima accetterà ancora la chiave revocata e non conoscerà
        ancora quella sostitutiva.
      operationId: authentication_get_jwks
      responses:
        '200':
          description: Le chiavi pubblicate.
          headers:
            Cache-Control:
              description: >-
                `public, max-age=300`: tu e le cache condivise potete conservare
                una risposta riuscita per 5 minuti, la durata di un token di
                accesso.
              schema:
                type: string
                example: public, max-age=300
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JSONWebKeySet'
              examples:
                Keys:
                  summary: Una chiave di firma
                  value:
                    keys:
                      - kty: EC
                        crv: P-256
                        x: ZDN2unLMultuZwNY_ZKMvsKLRrlC_usPFZyK77cnDO8
                        'y': CfLKoaJNvhFpDWqG56H8dD_j0f1c93RdR63bhIdTh3I
                        kid: k_8sJ2dQvX0nLr5TfYb3HkPw
                        use: sig
                        alg: ES256
        '403':
          $ref: '#/components/responses/OriginNotAllowed'
        '404':
          $ref: '#/components/responses/ApplicationNotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/TemporarilyUnavailable'
      security:
        - {}
components:
  schemas:
    JSONWebKeySet:
      type: object
      description: >-
        Le chiavi pubbliche di firma pubblicate dell'applicazione. Di solito una
        sola chiave; due in concomitanza con una rotazione, quando la chiave
        successiva viene pubblicata un giorno prima della firma e la chiave
        precedente rimane pubblicata per un giorno dopo aver smesso.
      required:
        - keys
      properties:
        keys:
          type: array
          items:
            $ref: '#/components/schemas/JSONWebKey'
    JSONWebKey:
      type: object
      description: Una chiave pubblica P-256 in formato JWK (RFC 7517).
      required:
        - kty
        - crv
        - x
        - 'y'
        - kid
        - use
        - alg
      properties:
        kty:
          type: string
          enum:
            - EC
        crv:
          type: string
          enum:
            - P-256
        x:
          type: string
          description: La coordinata x del punto pubblico, base64url.
          example: ZDN2unLMultuZwNY_ZKMvsKLRrlC_usPFZyK77cnDO8
        'y':
          type: string
          description: La coordinata y del punto pubblico, base64url.
          example: CfLKoaJNvhFpDWqG56H8dD_j0f1c93RdR63bhIdTh3I
        kid:
          type: string
          description: >-
            ID della chiave, il `kid` nell'intestazione di ogni token firmato da
            questa chiave. I nuovi ID delle chiavi iniziano con `k_`.
          example: k_8sJ2dQvX0nLr5TfYb3HkPw
        use:
          type: string
          enum:
            - sig
        alg:
          type: string
          enum:
            - ES256
    Detail:
      type: object
      required:
        - detail
      properties:
        detail:
          type: string
          example: invalid_token
    OAuthError:
      title: OAuth error
      type: object
      description: Un errore OAuth (RFC 6749 sezione 5.2) o un errore di servizio.
      required:
        - error
      properties:
        error:
          type: string
          example: invalid_grant
  responses:
    OriginNotAllowed:
      description: >-
        La richiesta conteneva un `Origin` che non appartiene all'applicazione
        né è tra le origini consentite. Le richieste server non inviano alcun
        `Origin`.
      headers:
        Cache-Control:
          description: 'Sempre `no-store`: non memorizzare mai nella cache questa risposta.'
          schema:
            type: string
            example: no-store
        Pragma:
          description: Sempre `no-cache`.
          schema:
            type: string
            example: no-cache
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Detail'
          examples:
            OriginNotAllowed:
              summary: Origine non consentita
              value:
                detail: origin_not_allowed
    ApplicationNotFound:
      description: >-
        L'indirizzo appartiene a un'applicazione, ma l'Autenticazione non è
        attiva per essa; sull'indirizzo `apx.didit.me`, l'ID applicazione è
        sconosciuto. Un indirizzo che non appartiene ad alcuna applicazione
        viene rifiutato prima di raggiungere l'endpoint, e tale risposta non è
        in formato JSON.
      headers:
        Cache-Control:
          description: 'Sempre `no-store`: non memorizzare mai nella cache questa risposta.'
          schema:
            type: string
            example: no-store
        Pragma:
          description: Sempre `no-cache`.
          schema:
            type: string
            example: no-cache
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Detail'
          examples:
            ApplicationNotFound:
              summary: Applicazione sconosciuta
              value:
                detail: No Configuration matches the given query.
    RateLimited:
      description: >-
        Troppe richieste da questo indirizzo IP per questo endpoint oppure, su
        un `POST` o un `DELETE`, un bucket di protezione dai bot è vuoto.
        Nessuna operazione eseguita: attendi `Retry-After` secondi, poi riprova.
      headers:
        Retry-After:
          description: Secondi da attendere prima di effettuare un nuovo tentativo.
          schema:
            type: integer
            example: 60
        Cache-Control:
          description: 'Sempre `no-store`: non memorizzare mai nella cache questa risposta.'
          schema:
            type: string
            example: no-store
        Pragma:
          description: Sempre `no-cache`.
          schema:
            type: string
            example: no-cache
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Detail'
          examples:
            RateLimited:
              summary: Limite dell'endpoint
              value:
                detail: >-
                  Too many requests from this IP address. Please wait before
                  trying again. Expected available in 60 seconds.
            BotProtection:
              summary: Limite di protezione dai bot (POST e DELETE)
              value:
                detail: rate_limited Expected available in 2 seconds.
    TemporarilyUnavailable:
      description: >-
        Un servizio da cui dipende la richiesta è temporaneamente non
        disponibile. Riprova con backoff.
      headers:
        Cache-Control:
          description: 'Sempre `no-store`: non memorizzare mai nella cache questa risposta.'
          schema:
            type: string
            example: no-store
        Pragma:
          description: Sempre `no-cache`.
          schema:
            type: string
            example: no-cache
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/OAuthError'
          examples:
            TemporarilyUnavailable:
              summary: Riprova più tardi
              value:
                error: temporarily_unavailable

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.