> This page is for Piattaforma, version V4 (default).
> For other versions, use one of these documentation indexes:
> - V4 (default): https://next.developer.frame.io/platform/v4/llms.txt
> - V4 sperimentale: https://next.developer.frame.io/platform/v4-experimental/llms.txt
> - Versione precedente: https://next.developer.frame.io/platform/v2/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://next.developer.frame.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://next.developer.frame.io/_mcp/server.

# SDK Python Frame.io — Guida all'autenticazione

Questa guida spiega come eseguire l'autenticazione con l'API Frame.io usando l'**SDK Python Frame.io** (`frameio`). L'API V4 Frame.io usa [Adobe Identity Management Service (IMS)](https://developer.adobe.com/developer-console/docs/guides/authentication/), la piattaforma di identità OAuth 2.0 di Adobe. Si tratta di un riferimento autonomo per sviluppatori Python. Tutti gli esempi di codice e i flussi seguenti sono solo per il pacchetto `frameio`.

---

## Tipi di autenticazione nell'SDK Python

L'SDK Python supporta quattro opzioni di autenticazione:

| Metodo                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Caso d'uso                                                                  | Interazione utente? | Richiede un secret del client? |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------------- | ------------------------------ |
| **Token statico**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | Script rapidi, test o se hai già un token                                   | No                  | No                             |
| **Server-to-server**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Servizi di backend, cron job, automazione                                   | No                  | Sì                             |
| **Web app**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | Applicazioni lato server (Flask, Django, FastAPI)                           | Sì                  | Sì                             |
| **SPA (PKCE)**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Applicazioni browser, CLI o qualsiasi app che non può memorizzare un secret | Sì                  | No                             |
| **Server-to-server** consente alla tua app di fungere da account servizio senza interazione utente. È disponibile solo per gli account Frame.io V4 amministrati tramite [Adobe Admin Console](https://adminconsole.adobe.com/).**Web app** e **SPA** consentono all'app di agire da utente specifico.Entrambi utilizzano Adobe IMS in background: l'utente autorizza la tua app e l'SDK scambia il codice risultante con i token. L'SDK Python gestisce per te il flusso IMS `/authorize/v2` e `/token/v3`. Per Web app hai bisogno di un secret del client; per SPA usi invece [PKCE](https://datatracker.ietf.org/doc/html/rfc7636). |                                                                             |                     |                                |

> **Note**
>
> La [credenziale dell'app nativa](https://developer.adobe.com/developer-console/docs/guides/authentication/UserAuthentication/implementation/#oauth-native-app-credential) di Adobe richiede dei gestori di schema URI personalizzati (ad esempio `adobe+<hash>://…</hash>`) che intercettano i reindirizzamenti a livello del sistema operativo. Python non ha un modo standard per registrare tali gestori, quindi l'SDK Python non offre una classe `NativeAppAuth`. Per le applicazioni Python interattive, usa `WebAppAuth` con un server di callback locale (ad esempio Flask o FastAPI). Per i carichi di lavoro non interattivi, usa `ServerToServerAuth`.

---

## Utenti dell'account di servizio

Quando usi l'autenticazione server-to-server, l'applicazione agisce come **utente dell'account di servizio**, un tipo di account distinto che può eseguire azioni per conto del servizio. Questi sono visibili agli altri utenti in Frame.io: quando un account di servizio esegue un'azione, il nome viene visualizzato nell'interfaccia utente. Puoi concedere e revocare l'accesso dell'account di servizio tramite [Adobe Admin Console](https://adminconsole.adobe.com/) e [Developer Console](https://developer.adobe.com/console). I nomi degli account di servizio vengono gestiti dall'interfaccia utente Frame.io. Per impostazione predefinita, la prima connessione S2S viene denominata **Service Account User**, la seconda **Service Account User 2** e così via.

> **Info**
>
> Consulta [Automatizza la configurazione usando il supporto server-to-server di Frame.io](https://helpx.adobe.com/enterprise/using/automate-using-frame-io.html) per ulteriori informazioni.

---

## Avvio rapido

### Prerequisiti

1. **Credenziali** da [Adobe Developer Console](https://developer.adobe.com/console):

* **ID client**: richiesto per tutti i flussi OAuth - **Secret client**: richiesto per i flussi server-to-server e web app - **URI di reindirizzamento**: richiesto per i flussi web app e SPA; deve essere registrato nel progetto Adobe

2. **Installa l'SDK:**

```bash
pip install frameio
```

### Scelta di un metodo

* **Non è coinvolto nessun utente?** Usa **server-to-server** (`ServerToServerAuth`).
* **È coinvolto un utente e puoi archiviare un secret?** Usa **web app** (`WebAppAuth`).
* **È coinvolto un utente, ma non puoi archiviare un secret?** Usa **SPA** (`SPAAuth`).

---

## Token di accesso

Se hai già un token di accesso (da un altro sistema OAuth o da uno scambio precedente, ad esempio tramite il nostro [Explorer di API](/platform/api-reference/accounts/index?explorer=true)) puoi passarlo direttamente:

```python
from frameio import Frameio

client = Frameio(token="YOUR_ACCESS_TOKEN")
```

Questo è l'approccio più semplice, ma il token scadrà e l'SDK non lo aggiornerà automaticamente.

### Token sviluppatore legacy

Per gli account migrati a V4 e non ancora amministrati tramite [Adobe Admin Console](https://adminconsole.adobe.com/), puoi continuare a utilizzare i token sviluppatore legacy dal [sito per sviluppatori di Frame.io](https://developer.frame.io/app/tokens). Devi includere l'intestazione `x-frameio-legacy-token-auth` e impostarla su `true`:

```python
from frameio import Frameio

client = Frameio(
    token="YOUR_LEGACY_DEVELOPER_TOKEN",
    headers={"x-frameio-legacy-token-auth": "true"},
)
```

I token sviluppatore legacy non scadono, ma sono un meccanismo di transizione. Per le nuove integrazioni e i carichi di lavoro di produzione, consigliamo di utilizzare uno dei flussi OAuth 2.0 indicati di seguito. Consulta la [guida alla migrazione](/platform/docs/resources/migration#authentication) per i dettagli.

---

## Server-to-server (credenziali client)

Utilizza questo metodo per servizi e script backend che necessitano dell'accesso a Frame.io senza interazioni da parte dell'utente. Questo flusso è disponibile solo per gli account Frame.io V4 amministrati tramite [Adobe Admin Console](https://adminconsole.adobe.com/). La tua applicazione si autentica come [utente dell'account di servizio](#service-account-users) senza intervento umano.

#### Sync

```python
    from frameio import Frameio
    from frameio.auth import ServerToServerAuth

    auth = ServerToServerAuth(
        client_id="YOUR_CLIENT_ID",
        client_secret="YOUR_CLIENT_SECRET",
    )

    client = Frameio(token=auth.get_token)
```

#### Async

```python
    from frameio import AsyncFrameio
    from frameio.auth import AsyncServerToServerAuth

    auth = AsyncServerToServerAuth(
        client_id="YOUR_CLIENT_ID",
        client_secret="YOUR_CLIENT_SECRET",
    )

    client = AsyncFrameio(token=auth.get_token)
```

Ecco fatto. `auth.get_token` è una funzione che l'SDK richiama a ogni richiesta. Se il token corrente è ancora valido, restituisce immediatamente il risultato. Se sta per scadere, ne recupera prima uno nuovo, in modo completamente trasparente.

### Come funziona

Le tue credenziali client (ID client + secret) **non scadono mai**. Basta ruotarle manualmente per garantire l'integrità della sicurezza. S2S offre un accesso API permanente e ininterrotto senza alcun intervento manuale.

Dietro le quinte:

1. Alla prima chiamata API, `get_token` richiede un nuovo token di accesso da Adobe IMS utilizzando la concessione `client_credentials`.
2. Il token viene memorizzato nella cache in memoria. I singoli token di accesso scadono (in genere 24 ore), ma questo viene gestito automaticamente.
3. Quando un token memorizzato nella cache si trova entro il buffer di aggiornamento (predefinito: 60 secondi prima della scadenza), l'SDK ne recupera automaticamente uno nuovo utilizzando le stesse credenziali client.
4. Non sono coinvolti token di aggiornamento. Le credenziali client stesse sono il secret di lunga durata e possono sempre essere utilizzate per generare un nuovo token di accesso.

### Autenticazione esplicita

Se desideri recuperare il token in modo proattivo (ad esempio, per generare rapidamente un errore in caso di credenziali errate all'avvio):

```python
auth = ServerToServerAuth(client_id="...", client_secret="...")
auth.authenticate()  # raises AuthenticationError if credentials are invalid
client = Frameio(token=auth.get_token)
```

---

## Web app (codice di autorizzazione)

Utilizza questo metodo per applicazioni lato server in cui gli utenti accedono con il proprio Adobe ID. Questo flusso richiede un client secret, che deve essere archiviato in modo sicuro sul server.

#### Reindirizza l'utente ad Adobe IMS

#### Sync

```python
    auth.refresh()  # fetches a new access token using the refresh token
```

#### Async

```python
    await auth.refresh()
```

#### Gestisci il callback

Quando Adobe IMS reindirizza l'utente al tuo `redirect_uri`, estrai i parametri `code` e `state`.Verifica che lo stato corrisponda a quello che hai archiviato, quindi scambia il codice con i token:

#### Sync

```python
    auth.refresh()  # fetches a new access token using the refresh token
```

#### Async

```python
    await auth.refresh()
```

Questa operazione scambia il codice di autorizzazione con un token di accesso e un token di aggiornamento, archiviandoli entrambi internamente.

#### Usa il client

#### Sync

```python
        from frameio import Frameio

        client = Frameio(token=auth.get_token)
```

#### Async

```python
        from frameio import AsyncFrameio

        client = AsyncFrameio(token=auth.get_token)
```

Ecco fatto. Da questo punto in poi, `get_token` gestisce automaticamente il ciclo di vita del token. Quando il token di accesso si avvicina alla scadenza, l'SDK usa il token di aggiornamento per ottenerne uno nuovo. Non è richiesta alcuna interazione da parte dell'utente.

### Esempio completo di Flask

```python
import secrets
from flask import Flask, redirect, request, session
from frameio import Frameio
from frameio.auth import WebAppAuth

app = Flask(__name__)
app.secret_key = secrets.token_bytes(32)

auth = WebAppAuth(
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET",
    redirect_uri="http://localhost:5000/callback",
)

@app.route("/login")
def login():
    state = secrets.token_urlsafe(32)
    session["oauth_state"] = state
    return redirect(auth.get_authorization_url(state=state))

@app.route("/callback")
def callback():
    if request.args.get("state") != session.pop("oauth_state", None):
        return "Invalid state parameter", 403

    auth.exchange_code(code=request.args["code"])

    client = Frameio(token=auth.get_token)
    accounts = client.accounts.index()
    return f"Authenticated — {len(accounts.data)} account(s) accessible."
```

---

## App a singola pagina/PKCE (codice di autorizzazione + PKCE)

Utilizza questa opzione per applicazioni basate su browser, applicazioni desktop o strumenti CLI che non possono archiviare in modo sicuro un secret del client. Questo flusso utilizza [PKCE (RFC 7636)](https://datatracker.ietf.org/doc/html/rfc7636) per proteggere lo scambio del codice di autorizzazione.

#### Genera l'URL di autorizzazione

#### Sync

```python
        from frameio.auth import SPAAuth

        auth = SPAAuth(
            client_id="YOUR_CLIENT_ID",
            redirect_uri="https://yourapp.com/callback",
        )

        import secrets
        state = secrets.token_urlsafe(32)

        result = auth.get_authorization_url(state=state)
        # result.url            -> redirect the user here
        # result.code_verifier  -> store this securely until the callback
```

#### Async

```python
        from frameio.auth import AsyncSPAAuth

        auth = AsyncSPAAuth(
            client_id="YOUR_CLIENT_ID",
            redirect_uri="https://yourapp.com/callback",
        )

        # get_authorization_url is synchronous (no I/O needed)
        import secrets
        state = secrets.token_urlsafe(32)

        result = auth.get_authorization_url(state=state)
```

`get_authorization_url` restituisce un `AuthorizationUrlResult` che contiene l'URL completo (con il PKCE `code_challenge` incorporato) e il `code_verifier` necessario per il passaggio successivo.

#### Scambia il codice con il verificatore

Quando l'utente viene reindirizzato:

#### Sync

```python
        auth.exchange_code(
            code="CODE_FROM_CALLBACK",
            code_verifier=result.code_verifier,
        )
```

#### Async

```python
        await auth.exchange_code(
            code="CODE_FROM_CALLBACK",
            code_verifier=result.code_verifier,
        )
```

#### Usa il client

#### Sync

```python
        from frameio import Frameio

        client = Frameio(token=auth.get_token)
```

#### Async

```python
        from frameio import AsyncFrameio

        client = AsyncFrameio(token=auth.get_token)
```

Ecco fatto. L'aggiornamento funziona come per web app: l'SDK usa automaticamente il token di aggiornamento. La differenza è che, durante l'aggiornamento, non viene inviato alcun secret del client, poiché il flusso SPA è progettato per client pubblici.

---

## Utilizzo asincrono

Ogni classe di autenticazione ha una controparte asincrona con prefisso `Async`. Gli esempi di codice in alto includono le schede **Sync** e **Async**, ove applicabile.

| Sync                                                                                                                                                                                          | Async                     |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| `ServerToServerAuth`                                                                                                                                                                          | `AsyncServerToServerAuth` |
| `WebAppAuth`                                                                                                                                                                                  | `AsyncWebAppAuth`         |
| `SPAAuth`                                                                                                                                                                                     | `AsyncSPAAuth`            |
| L'API è identica. `get_authorization_url` rimane sincrono (nessun I/O), mentre `exchange_code`, `refresh`, `revoke` e `get_token` sono tutti `async`. Usa le classi async con `AsyncFrameio`. |                           |

### Aggiornamento manuale del token

Per i flussi di web app e SPA, l'SDK aggiorna automaticamente i token tramite `get_token`. Se hai bisogno di un controllo esplicito, puoi chiamare direttamente `refresh()`:

#### Sync

```python
    auth.refresh()  # fetches a new access token using the refresh token
```

#### Async

```python
    await auth.refresh()
```

Questo è utile quando vuoi forzare un aggiornamento prima di un'operazione critica anziché affidarti al buffer di aggiornamento automatico.

---

## Persistenza del token

Tutte le classi di autenticazione supportano `export_tokens()` e `import_tokens()` per mantenere lo stato del token durante i riavvii. Questo è particolarmente importante per i flussi di web app e SPA, poiché i token di accesso e di aggiornamento risiedono in memoria per impostazione predefinita. Se l'applicazione si riavvia, gli utenti dovrebbero autenticarsi nuovamente, a meno che non li rendi persistenti. Per gli scenari server-to-server, la persistenza è facoltativa (le credenziali client possono sempre generare un nuovo token), ma l'importazione di un token memorizzato in cache evita un round-trip aggiuntivo all'avvio.

### Esportazione e importazione

```python
# After exchange_code(), save the token state
token_data = auth.export_tokens()
# token_data is a dict: {"access_token": "...", "refresh_token": "...", "expires_at": 1234567890.0}
# Save it to your database, file, or secret store

# On next startup, restore it
auth.import_tokens(token_data)
client = Frameio(token=auth.get_token)
# The SDK will automatically refresh if the token is near expiry
```

### Persistenza automatica con `on_token_refreshed`

Per rendere automaticamente persistenti i token ogni volta che vengono aggiornati, usa il callback `on_token_refreshed`:

```python
import json
from pathlib import Path

TOKEN_FILE = Path("tokens.json")

def save_tokens(tokens: dict):
    TOKEN_FILE.write_text(json.dumps(tokens))

auth = WebAppAuth(
    client_id="...",
    client_secret="...",
    redirect_uri="...",
    on_token_refreshed=save_tokens,
)

# On startup, restore if available
if TOKEN_FILE.exists():
    auth.import_tokens(json.loads(TOKEN_FILE.read_text()))
```

Il callback riceve la stessa forma di dict di `export_tokens()` e si attiva dopo ogni aggiornamento riuscito del token.Per le classi async, `on_token_refreshed` può essere una funzione normale o una funzione `async`. Sono supportate entrambe.

---

## Revoca dei token

Per disconnettere un utente e invalidare i suoi token con Adobe IMS:

```python
auth.revoke()
```

Esegue una richiesta di revoca best-effort ad Adobe IMS sia per il token di accesso che per il token di aggiornamento, quindi cancella tutto lo stato dei token locali. Dopo la revoca, l'utente dovrà autenticarsi di nuovo.

> **Tip**
>
> Per le classi async, usa `await auth.revoke()`.

---

## Gestione degli errori

Tutti gli errori di autenticazione ereditano da `FrameioAuthError`, quindi puoi intercettarli in modo generale o gestire casi specifici:

```python
from frameio.auth import (
    FrameioAuthError,
    AuthenticationError,
    TokenExpiredError,
    ConfigurationError,
    NetworkError,
    RateLimitError,
)

try:
    auth.exchange_code(code="...")
except TokenExpiredError:
    # The refresh token has expired; redirect the user to sign in again
    pass
except AuthenticationError as e:
    # Token exchange failed
    print(f"Error: {e.error_code} - {e.error_description}")
except NetworkError:
    # Timeout or connection failure (after retries)
    pass
except RateLimitError as e:
    # 429 from Adobe IMS; retry after e.retry_after seconds
    pass
except FrameioAuthError:
    # Catch-all for any other auth error
    pass
```

### Riferimento dell'errore

| Eccezione             | Quando viene generato                                                                                  |
| --------------------- | ------------------------------------------------------------------------------------------------------ |
| `ConfigurationError`  | Configurazione mancante o non valida (ad esempio `client_id` vuoto, URI di reindirizzamento non HTTPS) |
| `AuthenticationError` | Scambio o aggiornamento del token rifiutato da Adobe IMS (con `.error_code` e `.error_description`)    |
| `TokenExpiredError`   | Il token di aggiornamento stesso è scaduto; l'utente deve eseguire nuovamente l'autenticazione         |
| `NetworkError`        | Timeout HTTP o errore di connessione dopo tutti i tentativi                                            |
| `RateLimitError`      | Adobe IMS ha restituito un errore 429; controlla `.retry_after` per indicazioni sul backoff            |
| `PKCEError`           | Verifica PKCE non riuscita (flusso SPA)                                                                |

### Gestione dei token di aggiornamento scaduti in produzione

> **Warning**
>
> Per i flussi di web app e SPA, il token di aggiornamento scadrà.Quando ciò accade, `get_token` genera `TokenExpiredError`. Devi intercettare questo errore e reindirizzare l'utente attraverso il flusso di autorizzazione.

```python
from frameio.auth import TokenExpiredError

try:
    client = Frameio(token=auth.get_token)
    assets = client.files.list(project_id="...")
except TokenExpiredError:
    # Clear persisted tokens and redirect user to login
    auth.revoke()
    return redirect("/login")
```

---

## Riferimento della configurazione

Tutte le classi di autorizzazione accettano questi parametri opzionali:

#### Riferimento dei parametri

| Parametro            | Predefinito                                       | Descrizione                                                                                                                                                                                                                        |
| -------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scopes`             | Impostazioni predefinite specifiche per il flusso | Ambiti OAuth separati da spazio. S2S ha come impostazione predefinita `openid AdobeID frame.s2s.all`; i flussi rivolti all'utente hanno come impostazione predefinita `openid email profile offline_access additional_info.roles`. |
| `ims_base_url`       | `https://ims-na1.adobelogin.com`                  | URL di base di Adobe IMS. Sostituisce gli ambienti temporanei o non di produzione.                                                                                                                                                 |
| `http_client`        | `None`                                            | `httpx.Client` personalizzato (o `httpx.AsyncClient`) per proxy, mTLS o pooling delle connessioni.                                                                                                                                 |
| `timeout`            | `30`                                              | Timeout della richiesta HTTP in secondi per le chiamate endpoint del token.                                                                                                                                                        |
| `max_retries`        | `2`                                               | Numero massimo di nuovi tentativi per errori temporanei (5xx, timeout). I nuovi tentativi per limite di frequenza (429) vengono tracciati separatamente.                                                                           |
| `refresh_buffer`     | `60`                                              | Secondi prima della scadenza del token per attivare l'aggiornamento proattivo.                                                                                                                                                     |
| `on_token_refreshed` | `None`                                            | Callback attivato dopo ogni aggiornamento riuscito del token. Riceve un dict con `access_token`, `refresh_token` e `expires_at`.                                                                                                   |

### Ambienti temporanei

Punta a un'istanza Adobe IMS temporanea sostituendo `ims_base_url`. L'SDK esporta anche `DEFAULT_IMS_BASE_URL` (`https://ims-na1.adobelogin.com`) se devi fare riferimento al valore di produzione a livello programmatico.

```python
auth = ServerToServerAuth(
    client_id="...",
    client_secret="...",
    ims_base_url="https://ims-na1-stg1.adobelogin.com",
)
```

### Client HTTP personalizzato

Per il supporto proxy o la configurazione TLS personalizzata:

```python
import httpx

http_client = httpx.Client(
    proxy="http://corporate-proxy:8080",
    verify="/path/to/custom-ca-bundle.pem",
)

auth = ServerToServerAuth(
    client_id="...",
    client_secret="...",
    http_client=http_client,
)
```

---

## Sicurezza dei thread

Le classi di autenticazione sincronizzate sono completamente thread-safe. Se più thread chiamano `get_token` contemporaneamente ed è necessario un aggiornamento, solo un thread esegue l'aggiornamento. Gli altri attendono e ricevono lo stesso risultato. Non è richiesto alcun blocco esterno. Le classi asincrone offrono la stessa garanzia utilizzando `asyncio.Lock`, sicuro per coroutine simultanee all'interno di un singolo ciclo di eventi.