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

# Migrar usuaris: importar contrasenyes i MFA

> Importa usuaris amb contrasenyes, correus verificats, vincles socials, apps d'autenticació i rols d'organització des de CSV, JSON o lots amb Didit.

> [!WARNING]
>
> L'autenticació és nova. Executa cada importació primer en una aplicació sandbox i després importa-la a la teva aplicació en producció.

Una importació trasllada persones d'una altra plataforma d'identitat a Didit Authentication. La seva contrasenya, el correu electrònic verificat, els enllaços d'inici de sessió social, l'aplicació d'autenticació i els rols d'organització es traslladen amb elles. Per a elles no canvia res fins que la teva aplicació les faci iniciar sessió amb Didit.

Les importacions utilitzen l'API de gestió d'autenticació de la teva aplicació amb una sessió de la consola que tingui `write:authentication` (o `read:authentication` per llistar-les). Mai no utilitzen un token d'usuari final ni una clau d'API de verificació. En els exemples, `MANAGEMENT_BASE` és:

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

## Dues maneres d'importar

| | Tasca de fitxer | Sol·licitud per lots |
| - | - | - |
| Endpoint | `POST import-jobs/` (multipart) | `POST imports/` (JSON) |
| Mida | Un fitxer CSV o JSON, de fins a 25 MB i 100.000 persones | De 1 a 1.000 `rows` per sol·licitud |
| Simulació | Sempre s'executa primer, en segon pla | `dry_run: true` per defecte |
| Confirmació | `POST import-jobs/{id}/start/` | La mateixa sol·licitud amb `dry_run: false` |
| Fallada parcial | Cada lot de 1.000 es confirma per separat; una importació interrompuda es reprèn | Tot o res |

## Importar un fitxer

### 1. Pujada

```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
```

| Camp | Significat |
| - | - |
| `file` | CSV o JSON, en UTF-8 (es permet una marca d'ordre de bytes), de fins a 25 MB. |
| `passwords` | `import` (el valor per defecte) conserva els hashes de les contrasenyes. `reset` els ignora, de manera que tothom haurà d'establir una contrasenya nova. |
| `keep_social` | Conserva els enllaços d'inici de sessió social. |
| `keep_verified` | Conserva `email_verified`. Amb `false`, tots els correus electrònics es marquen com a no verificats. |
| `keep_mfa` | Conserva els secrets de l'aplicació d'autenticació. |
| `keep_ids` | Conserva `external_id`. Amb `false`, `vendor_data` es converteix en l'ID d'identitat de Didit. |
| `firebase_signer_key`, `firebase_salt_separator`, `firebase_rounds`, `firebase_mem_cost` | Els paràmetres de hash del teu projecte de Firebase. Envia'ls tots quatre o cap. |

Cada interruptor `keep_*` és `true` tret que enviïs `false`. La crida retorna `202` amb una tasca. Una aplicació pot tenir com a màxim 5 fitxers pujats alhora.

### 2. Comprova la simulació

Cada pujada inicia una simulació. La simulació revisa cada persona i no escriu res. Consulta `GET import-jobs/{id}/`:

| Camp | Significat |
| - | - |
| `kind` | `dry_run`, i després `import` quan l'iniciis. |
| `status` | `queued`, `running`, i després `passed` o `failed` per a una simulació, o `done` o `error` per a una importació. |
| `processed`, `total` | Progrés, en persones. |
| `result` | El contingut del fitxer (consulta [resultats](#resultats)). |
| `startable` | `true` quan la simulació ha estat satisfactòria i el fitxer no ha caducat. |
| `expires_at` | El fitxer s'elimina 24 hores després d'una simulació que no ha anat seguida d'una importació. |

Una simulació fallida enumera els seus errors. Corregeix el fitxer i torna a pujar-lo.

### 3. Inicia la importació

`POST import-jobs/{id}/start/` importa el que va revisar la simulació i retorna `202`.

* Les persones s'importen en lots de 1.000. Cada lot es confirma per separat.
* Només s'executa una importació alhora per aplicació (en cas contrari, `import_running`).
* Una importació interrompuda es reprèn després de l'últim lot confirmat.
* Les persones ja importades s'ometen, de manera que pots executar el mateix fitxer una altra vegada.
* La persona que ha iniciat la importació rep un correu electrònic quan acaba o s'atura.

El fitxer pujat s'emmagatzema xifrat. S'elimina quan acaba la importació, quan falla la seva simulació, o 24 hores després d'una simulació que mai no s'ha importat.

## Importar per lots

Envia fins a 1.000 persones per sol·licitud, amb una `idempotency_key` de fins a 100 caràcters.

```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"
}
```

* Una simulació retorna `200` amb el resultat i no escriu res.
* Amb `dry_run: false`, una importació correcta retorna `201`. Un lot amb qualsevol error retorna `400` i no importa ningú.
* Si repeteixes una sol·licitud confirmada amb la mateixa clau, es retorna el resultat registrat. La mateixa clau amb un contingut diferent retorna `400 {"idempotency_key": "different_payload"}`.
* Els paràmetres de Firebase van en un objecte `firebase`: `{signer_key, salt_separator, rounds, mem_cost}`.
* `GET imports/` llista els lots confirmats.

## Format del fitxer

### JSON

Una matriu de persones, o un objecte amb la matriu dins de `users`.

| Camp | Regla |
| - | - |
| `email` | Obligatori. |
| `external_id` | Fins a 255 caràcters. Es converteix en el [`vendor_data`](https://docs.didit.me/ca/entities/vendor-data-linking) de la persona. |
| `email_verified` | `true` o `false` (també `1`/`0`, `yes`/`no`). |
| `display_name` | Fins a 200 caràcters. |
| `password_hash`, `password_salt`, `password_algorithm` | Consulta [contrasenyes](#contrasenyes). |
| `totp_secret` | Secret de l'aplicació d'autenticació en Base32. |
| `created_at`, `last_signed_in_at` | ISO 8601. Una hora sense zona s'interpreta com a UTC. |
| `social` | Fins a 8 `{provider, subject, tenant_id}`. `provider` és `google`, `apple`, `github` o `microsoft`. `tenant_id` és obligatori només per a Microsoft. |
| `organizations` | Fins a 20 `{slug, name, role}`. `role` és `admin`, `member` (el valor per defecte) o `billing`. |

### CSV

Les mateixes columnes de valor únic, més `google_id`, `apple_id`, `github_id`, `microsoft_id`, `microsoft_tenant_id`, `organization_slug`, `organization_name` i `organization_role`. Una persona en diverses organitzacions ocupa una línia per organització.

```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
```

Els camps o les columnes desconeguts són errors, mai s'ignoren.

### Duplicats i comptes existents

* Les línies amb el mateix correu electrònic es converteixen en una sola persona. Una línia idèntica es compta com a duplicat. Una línia amb més enllaços, organitzacions o una aplicació d'autenticació es fusiona.
* Dos hashes de contrasenya, secrets d'autenticació o rols d'organització diferents per a una mateixa persona són errors. També ho és un `external_id` o un subjecte del proveïdor que reclamin dues persones diferents.
* Si ja existeix un compte amb aquest correu electrònic i una importació anterior l'ha creat, la persona s'omet (`already_imported`). Si la persona es va registrar per si mateixa, es produeix un error `identity_conflict`. Una importació mai no modifica un compte existent.

## Contrasenyes

| Format | Acceptat |
| - | - |
| bcrypt | `$2a$`, `$2b$` o `$2y$`, cost de 4 a 13. |
| Argon2id | `$argon2id$v=19$...`. Fins a 64 MiB de memòria, memòria multiplicada pel nombre de passades fins a 256 MiB, fins a 8 carrils. |
| Django PBKDF2-SHA256 | `pbkdf2_sha256$...`, de 10.000 a 2.000.000 d'iteracions. |
| Django scrypt | `scrypt$...`, factor de treball fins a 32.768, mida de bloc d'1 a 8, paral·lelisme d'1 a 5. |
| Firebase scrypt | `password_algorithm: "firebase_scrypt"`, `password_hash` i `password_salt` en base64 per persona, i a més el `signer_key`, `salt_separator`, `rounds` (d'1 a 8) i `mem_cost` (d'1 a 14) del teu projecte, una vegada per importació. |

Els paràmetres de Firebase s'emmagatzemen xifrats, només per a aquesta aplicació. Qualsevol altre format, o un cost per sobre d'aquests límits, vol dir que la persona necessita una contrasenya nova. Després del primer inici de sessió satisfactori d'una persona, Didit torna a emmagatzemar la seva contrasenya en el seu propi format.

### Persones sense una contrasenya utilitzable

Quan una persona no té hash, o en té un que no és compatible, un intent d'inici de sessió amb contrasenya rep la resposta habitual d'error de contrasenya. Didit també li envia per correu un enllaç per establir una contrasenya nova (vàlid durant 30 minuts, com a màxim un cop al dia). Això només passa quan el seu correu està verificat, el compte no està bloquejat i l'inici de sessió amb contrasenya està activat.

Al resultat, `reset_required` compta les persones sense una contrasenya utilitzable. `reset_emails` compta les que tenen un correu verificat entre elles: només aquestes es poden contactar d'aquesta manera. Les persones amb un correu no verificat no poden iniciar sessió amb contrasenya. Encara poden iniciar sessió amb un codi per correu si actives aquest mètode.

## Vincles socials, autenticadors i organitzacions

* **Vincles socials** es conserven per als proveïdors que la teva aplicació ja té configurats, amb el seu ID de client actual. Un inici de sessió posterior no necessita llavors cap prova del correu. Els subjectes de Google i GitHub són globals. Els subjectes d'Apple són per equip de desenvolupament i els de Microsoft per registre d'aplicació, de manera que aquests vincles només coincideixen si la teva plataforma antiga feia servir el mateix equip o registre. Els vincles amb proveïdors que no has configurat es compten com a `social_unavailable` i no s'importen.
* **Aplicacions d'autenticació** (secrets TOTP: SHA-1, 6 dígits, 30 segons): els seus secrets s'emmagatzemen xifrats. Les persones importades han de fer-les servir com a segon factor. No reben codis de recuperació.
* **Organitzacions** que encara no existeixen es creen a partir del seu slug.
* **Claus d'accés** no es poden importar. Pertanyen al teu antic domini d'inici de sessió, de manera que les persones n'afegeixen una de nova després d'iniciar sessió amb Didit.

## Resultats

Cada execució de prova, lot i tasca retorna el mateix `result`:

| Camp | Significat |
| - | - |
| `rows`, `people_total` | Línies llegides i persones diferents. |
| `ready`, `already_imported`, `duplicates`, `merged`, `skipped` | Què passa amb cada persona. |
| `passwords` | Recomptes per format: `bcrypt`, `argon2id`, `firebase_scrypt`, `pbkdf2_sha256`, `scrypt`. |
| `reset_required`, `reset_emails`, `unsupported_hashes` | Persones que necessiten una contrasenya nova. |
| `verified_emails` | Persones importades amb un correu verificat. |
| `social_links`, `social_unavailable` | Vincles conservats per proveïdor, i vincles omesos. |
| `authenticator_apps` | Persones amb un autenticador importat. |
| `organizations` | `count`, `members` i fins a cinc `names`. |
| `error_count`, `errors` | Fins a 100 errors, cadascun amb una `row` indexada a partir de zero (línia del CSV `row + 2`), un `field` i un codi `error`. |

Les respostes no contenen mai hashes de contrasenyes, sals, secrets d'autenticadors ni valors de camps.

| Error | Significat |
| - | - |
| `file_too_large`, `too_many_rows`, `empty_file` | Més de 25 MB, més de 100.000 persones, o buit. |
| `invalid_encoding`, `invalid_json`, `invalid_csv` | No es pot llegir el fitxer. |
| `unknown_column`, `missing_column`, `duplicate_column`, `unknown_field` | El fitxer no coincideix amb el format. |
| `required`, `invalid_field`, `invalid_row` | Falta un valor o és invàlid. |
| `identity_conflict` | Un compte amb aquest correu s'ha registrat pel seu compte. |
| `social_link_conflict`, `password_conflict`, `authenticator_conflict`, `role_conflict` | Dues línies per a una mateixa persona no coincideixen. |
| `too_many_uploads`, `import_running`, `not_startable`, `file_expired` | La tasca no es pot iniciar ara. |

## Abans de fer el canvi

Prova a la teva aplicació de sandbox:

* l'inici de sessió amb cada format de contrasenya que importes,
* el correu per establir una contrasenya nova per a una persona sense hash utilitzable,
* l'inici de sessió social i els codis d'autenticador per a les persones importades,
* l'execució del mateix fitxer dues vegades.

Després, comprova que el `vendor_data` de cada persona coincideix amb el valor que fas servir per a les seves [verificacions i transaccions](https://docs.didit.me/ca/authentication/overview.md#mantén-una-mateixa-persona-entre-productes).


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