> ## 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.

# Migrazione utenti: importare password e MFA

> Importa in Didit utenti con password, email verificate, link social, app di autenticazione e ruoli, da CSV, JSON o in batch.

> [!WARNING]
>
> Authentication è una novità. Esegui ogni importazione prima in un'applicazione sandbox, poi importa nella tua applicazione di produzione.

Un'importazione sposta le persone da un'altra piattaforma di identità a Didit Authentication. La loro password, l'email verificata, i collegamenti di accesso social, l'app di autenticazione e i ruoli nelle organizzazioni si spostano con loro. Per loro non cambia nulla finché la tua applicazione non le fa accedere con Didit.

Le importazioni usano l'API di gestione Authentication della tua applicazione, con una sessione della console che ha `write:authentication` (o `read:authentication` per elencarle). Non usano mai un token dell'utente finale né una chiave API di verifica. Negli esempi, `MANAGEMENT_BASE` è:

```text theme={null}
https://apx.didit.me/auth/v2/organizations/{org_id}/applications/{application_id}/authentication/
```

## Due modi per importare

| | Processo da file | Richiesta batch |
| - | - | - |
| Endpoint | `POST import-jobs/` (multipart) | `POST imports/` (JSON) |
| Dimensione | Un file CSV o JSON, fino a 25 MB e 100.000 persone | Da 1 a 1.000 `rows` per richiesta |
| Esecuzione di prova | Eseguita sempre per prima, in background | `dry_run: true` per impostazione predefinita |
| Conferma | `POST import-jobs/{id}/start/` | La stessa richiesta con `dry_run: false` |
| Errore parziale | Per ogni batch da 1.000 viene eseguito il commit separatamente; un'importazione interrotta riprende | Tutto o niente |

## Importare un file

### 1. Caricamento

```bash theme={null}
curl --fail-with-body "${MANAGEMENT_BASE}import-jobs/" \
  -H "Authorization: Bearer $CONSOLE_ACCESS_TOKEN" \
  -F file=@users.csv \
  -F passwords=import \
  -F keep_social=true \
  -F keep_verified=true \
  -F keep_mfa=true \
  -F keep_ids=true
```

| Campo | Significato |
| - | - |
| `file` | CSV o JSON, UTF-8 (è consentito un indicatore di ordine dei byte (BOM)), fino a 25 MB. |
| `passwords` | `import` (il valore predefinito) mantiene gli hash delle password. `reset` li ignora, quindi tutti impostano una nuova password. |
| `keep_social` | Mantiene i collegamenti di accesso social. |
| `keep_verified` | Mantiene `email_verified`. Con `false`, ogni email risulta non verificata. |
| `keep_mfa` | Mantiene i segreti dell'app di autenticazione. |
| `keep_ids` | Mantiene `external_id`. Con `false`, `vendor_data` diventa l'ID dell'identità Didit. |
| `firebase_signer_key`, `firebase_salt_separator`, `firebase_rounds`, `firebase_mem_cost` | I parametri di hash del tuo progetto Firebase. Inviali tutti e quattro o nessuno. |

Ogni interruttore `keep_*` è `true` a meno che tu non invii `false`. La chiamata restituisce `202` con un processo. Un'applicazione può avere al massimo 5 file caricati alla volta.

### 2. Verifica dell'esecuzione di prova

Ogni caricamento avvia un'esecuzione di prova. Controlla ogni persona e non scrive nulla. Interroga `GET import-jobs/{id}/`:

| Campo | Significato |
| - | - |
| `kind` | `dry_run`, poi `import` quando la avvii. |
| `status` | `queued`, `running`, poi `passed` o `failed` per un'esecuzione di prova, `done` o `error` per un'importazione. |
| `processed`, `total` | Avanzamento, in persone. |
| `result` | Cosa contiene il file (vedi [risultati](#risultati)). |
| `startable` | `true` quando l'esecuzione di prova è superata e il file non è scaduto. |
| `expires_at` | Il file viene eliminato 24 ore dopo un'esecuzione di prova per la quale l'importazione non è mai stata avviata. |

Un'esecuzione di prova fallita elenca i propri errori. Correggi il file e caricalo di nuovo.

### 3. Avvia l'importazione

`POST import-jobs/{id}/start/` importa ciò che l'esecuzione di prova ha verificato e restituisce `202`.

* Le persone vengono importate in batch da 1.000. Per ogni batch viene eseguito il commit separatamente.
* Per applicazione può essere in esecuzione una sola importazione alla volta (altrimenti `import_running`).
* Un'importazione interrotta riprende dopo l'ultimo batch confermato.
* Le persone già importate vengono saltate, quindi puoi eseguire di nuovo lo stesso file.
* Chi ha avviato l'importazione riceve un'email quando questa termina o si ferma.

Il file caricato viene memorizzato cifrato. Viene eliminato al termine dell'importazione, quando la sua esecuzione di prova fallisce, oppure 24 ore dopo un'esecuzione di prova per la quale l'importazione non è mai stata avviata.

## Importare in batch

Invia fino a 1.000 persone per richiesta, con un `idempotency_key` di massimo 100 caratteri.

```json theme={null}
{
  "rows": [
    {
      "email": "user@example.com",
      "external_id": "user-1234",
      "email_verified": true,
      "display_name": "Example User",
      "password_hash": "$2b$12$...",
      "social": [{ "provider": "google", "subject": "1234567890" }],
      "organizations": [{ "slug": "acme", "name": "Acme", "role": "admin" }]
    }
  ],
  "dry_run": true,
  "idempotency_key": "migration-batch-0001"
}
```

* Un'esecuzione di prova restituisce `200` con il risultato e non scrive nulla.
* Con `dry_run: false`, un'importazione riuscita restituisce `201`. Un batch con anche un solo errore restituisce `400` e non importa nessuno.
* Ripetere una richiesta già confermata con la stessa chiave restituisce il suo risultato registrato. La stessa chiave con contenuto diverso restituisce `400 {"idempotency_key": "different_payload"}`.
* I parametri Firebase vanno in un oggetto `firebase`: `{signer_key, salt_separator, rounds, mem_cost}`.
* `GET imports/` elenca i batch confermati.

## Formato del file

### JSON

Un array di persone, oppure un oggetto il cui campo `users` contiene l'array.

| Campo | Regola |
| - | - |
| `email` | Obbligatorio. |
| `external_id` | Fino a 255 caratteri. Diventa il [`vendor_data`](https://docs.didit.me/it/entities/vendor-data-linking) della persona. |
| `email_verified` | `true` o `false` (anche `1`/`0`, `yes`/`no`). |
| `display_name` | Fino a 200 caratteri. |
| `password_hash`, `password_salt`, `password_algorithm` | Vedi [password](#password). |
| `totp_secret` | Segreto dell'app di autenticazione in Base32. |
| `created_at`, `last_signed_in_at` | ISO 8601. Un orario senza fuso è in UTC. |
| `social` | Fino a 8 `{provider, subject, tenant_id}`. `provider` è `google`, `apple`, `github` o `microsoft`. `tenant_id` è obbligatorio solo per Microsoft. |
| `organizations` | Fino a 20 `{slug, name, role}`. `role` è `admin`, `member` (il valore predefinito) o `billing`. |

### CSV

Le stesse colonne con un solo valore, più `google_id`, `apple_id`, `github_id`, `microsoft_id`, `microsoft_tenant_id`, `organization_slug`, `organization_name` e `organization_role`. Una persona in più organizzazioni occupa una riga per ogni organizzazione.

```csv theme={null}
email,external_id,email_verified,password_hash,google_id,organization_slug,organization_role
user@example.com,user-1234,true,$2b$12$...,1234567890,acme,admin
```

Campi o colonne sconosciuti sono errori e non vengono mai ignorati.

### Duplicati e account esistenti

* Le righe con la stessa email diventano una sola persona. Una riga identica viene contata come duplicato. Una riga con più collegamenti, organizzazioni o un autenticatore viene unita.
* Due hash di password, segreti di autenticazione o ruoli nelle organizzazioni diversi per una stessa persona sono errori. Lo è anche un `external_id` o un subject di un provider rivendicato da due persone.
* Se esiste già un account con quell'email e un'importazione precedente lo ha creato, la persona viene saltata (`already_imported`). Se la persona si era registrata da sola, si tratta di un errore `identity_conflict`. Un'importazione non modifica mai un account esistente.

## Password

| Formato | Accettato |
| - | - |
| bcrypt | `$2a$`, `$2b$` o `$2y$`, costo da 4 a 13. |
| Argon2id | `$argon2id$v=19$...`. Fino a 64 MiB di memoria, il prodotto della memoria per il numero di passate fino a 256 MiB, fino a 8 lane. |
| Django PBKDF2-SHA256 | `pbkdf2_sha256$...`, da 10.000 a 2.000.000 di iterazioni. |
| Django scrypt | `scrypt$...`, fattore di lavoro fino a 32.768, dimensione del blocco da 1 a 8, parallelismo da 1 a 5. |
| Firebase scrypt | `password_algorithm: "firebase_scrypt"`, `password_hash` e `password_salt` in base64 per persona, più `signer_key`, `salt_separator`, `rounds` (da 1 a 8) e `mem_cost` (da 1 a 14) del tuo progetto, una volta per importazione. |

I parametri Firebase sono memorizzati cifrati, e solo per quella applicazione. Qualsiasi altro formato, o un costo superiore a questi limiti, significa che la persona deve impostare una nuova password. Dopo il primo accesso riuscito di una persona, Didit memorizza di nuovo la sua password nel proprio formato.

### Persone senza una password utilizzabile

Quando una persona non ha un hash, o ne ha uno non supportato, un tentativo di accesso con password riceve la normale risposta relativa a una password errata. Didit le invia inoltre via email un link per impostare una nuova password (valido 30 minuti, al massimo una volta al giorno). Ciò avviene solo se la sua email è verificata, l'account non è bloccato e l'accesso con password è attivo.

Nel risultato, `reset_required` conta le persone senza una password utilizzabile. `reset_emails` conta quelle tra loro con un'email verificata: solo loro possono essere raggiunte in questo modo. Le persone con un'email non verificata non possono accedere con una password. Possono comunque accedere con un codice via email, se abiliti questo metodo.

## Link social, app di autenticazione e organizzazioni

* **I link social** vengono mantenuti per i provider che la tua applicazione ha già configurato, con il client ID attuale. Un accesso successivo non richiede quindi una prova via email. I subject di Google e GitHub sono globali. I subject di Apple sono per team di sviluppatori e quelli di Microsoft per la registrazione dell'app, quindi questi link corrispondono solo se la vecchia piattaforma usava lo stesso team o la stessa registrazione. I link verso provider non configurati sono conteggiati come `social_unavailable` e non vengono importati.
* **Le app di autenticazione** (segreti TOTP: SHA-1, 6 cifre, 30 secondi): i segreti sono memorizzati cifrati. Le persone importate devono usarle come secondo fattore. Non ricevono codici di recupero.
* **Le organizzazioni** che non esistono ancora vengono create a partire dal loro slug.
* **Le passkey** non possono essere importate. Appartengono al vecchio dominio di accesso, quindi le persone aggiungono una nuova passkey dopo aver effettuato l'accesso con Didit.

## Risultati

Ogni simulazione, batch e job restituisce lo stesso `result`:

| Campo | Significato |
| - | - |
| `rows`, `people_total` | Righe lette e persone distinte. |
| `ready`, `already_imported`, `duplicates`, `merged`, `skipped` | Cosa succede a ciascuna persona. |
| `passwords` | Conteggi per formato: `bcrypt`, `argon2id`, `firebase_scrypt`, `pbkdf2_sha256`, `scrypt`. |
| `reset_required`, `reset_emails`, `unsupported_hashes` | Persone che devono impostare una nuova password. |
| `verified_emails` | Persone importate con un'email verificata. |
| `social_links`, `social_unavailable` | Link mantenuti per provider, e link saltati. |
| `authenticator_apps` | Persone con un'app di autenticazione importata. |
| `organizations` | `count`, `members` e fino a cinque `names`. |
| `error_count`, `errors` | Fino a 100 errori, ciascuno con un `row` a base zero (riga CSV `row + 2`), un `field` e un codice `error`. |

Le risposte non contengono mai hash delle password, salt, segreti degli autenticatori o valori dei campi.

| Errore | Significato |
| - | - |
| `file_too_large`, `too_many_rows`, `empty_file` | Oltre 25 MB, oltre 100.000 persone, oppure file vuoto. |
| `invalid_encoding`, `invalid_json`, `invalid_csv` | Il file non può essere letto. |
| `unknown_column`, `missing_column`, `duplicate_column`, `unknown_field` | Il file non corrisponde al formato. |
| `required`, `invalid_field`, `invalid_row` | Un valore manca o non è valido. |
| `identity_conflict` | Un account con quell'email si è registrato autonomamente. |
| `social_link_conflict`, `password_conflict`, `authenticator_conflict`, `role_conflict` | Due righe per una stessa persona non coincidono. |
| `too_many_uploads`, `import_running`, `not_startable`, `file_expired` | Il job non può essere avviato ora. |

## Prima di passare al nuovo sistema

Testa nella tua applicazione sandbox:

* l'accesso con ciascun formato di password che importi,
* l'email per impostare una nuova password per una persona senza un hash utilizzabile,
* l'accesso social e i codici degli autenticatori per le persone importate,
* l'esecuzione dello stesso file due volte.

Poi verifica che il `vendor_data` di ciascuna persona corrisponda al valore che usi per le sue [verifiche e transazioni](https://docs.didit.me/it/authentication/overview.md#mantieni-la-stessa-persona-tra-i-prodotti).


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