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

# Migração de usuários: importar senhas e MFA

> Importe usuários para o Didit com senhas, e-mails verificados, contas sociais, autenticadores e funções na organização, via CSV, JSON ou em lotes.

> [!WARNING]
>
> O Authentication é novo. Execute toda importação primeiro em uma aplicação sandbox e, depois, importe para a sua aplicação de produção.

Uma importação transfere pessoas de outra plataforma de identidade para o Didit Authentication. A senha, o e-mail verificado, os vínculos de login social, o app autenticador e as funções nas organizações vão junto com elas. Nada muda para essas pessoas até que a sua aplicação as autentique com a Didit.

As importações usam a API de gerenciamento do Authentication da sua aplicação, com uma sessão do console que tenha `write:authentication` (ou `read:authentication` para listá-las). Elas nunca usam um token de usuário final nem uma chave de API de verificação. Nos exemplos, `MANAGEMENT_BASE` é:

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

## Duas formas de importar

| | Tarefa de arquivo | Requisição em lote |
| - | - | - |
| Endpoint | `POST import-jobs/` (multipart) | `POST imports/` (JSON) |
| Tamanho | Um arquivo CSV ou JSON, de até 25 MB e 100,000 pessoas | De 1 a 1,000 `rows` por requisição |
| Simulação | Sempre é executada primeiro, em segundo plano | `dry_run: true` por padrão |
| Efetivação | `POST import-jobs/{id}/start/` | A mesma requisição com `dry_run: false` |
| Falha parcial | Cada lote de 1,000 pessoas é efetivado separadamente; uma importação interrompida é retomada | Tudo ou nada |

## Importar um arquivo

### 1. Enviar

```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 | Significado |
| - | - |
| `file` | CSV ou JSON, em UTF-8 (BOM é permitido), de até 25 MB. |
| `passwords` | `import` (o padrão) mantém os hashes de senha. `reset` os ignora, então todos definem uma nova senha. |
| `keep_social` | Mantém os vínculos de login social. |
| `keep_verified` | Mantém `email_verified`. Com `false`, todos os e-mails ficam não verificados. |
| `keep_mfa` | Mantém os segredos do app autenticador. |
| `keep_ids` | Mantém `external_id`. Com `false`, `vendor_data` passa a ser o ID de identidade da Didit. |
| `firebase_signer_key`, `firebase_salt_separator`, `firebase_rounds`, `firebase_mem_cost` | Os parâmetros de hash do seu projeto Firebase. Envie os quatro ou nenhum. |

Cada opção `keep_*` é `true`, a menos que você envie `false`. A chamada retorna `202` com um job. Uma aplicação mantém no máximo 5 arquivos enviados ao mesmo tempo.

### 2. Conferir a simulação

Todo envio inicia uma simulação. Ela verifica cada pessoa e não grava nada. Consulte `GET import-jobs/{id}/` periodicamente:

| Campo | Significado |
| - | - |
| `kind` | `dry_run` e, depois que você a inicia, `import`. |
| `status` | `queued`, `running` e depois `passed` ou `failed` em uma simulação, `done` ou `error` em uma importação. |
| `processed`, `total` | Progresso, em pessoas. |
| `result` | O que o arquivo contém (veja os [resultados](#resultados)). |
| `startable` | `true` quando a simulação foi aprovada e o arquivo não expirou. |
| `expires_at` | O arquivo é excluído 24 horas após uma simulação que nunca foi importada. |

Uma simulação com falha lista os seus erros. Corrija o arquivo e envie-o novamente.

### 3. Iniciar a importação

`POST import-jobs/{id}/start/` importa o que a simulação verificou e retorna `202`.

* As pessoas são importadas em lotes de 1,000. Cada lote é efetivado separadamente.
* Apenas uma importação é executada por aplicação de cada vez (caso contrário, `import_running`).
* Uma importação interrompida é retomada após o último lote efetivado.
* As pessoas já importadas são ignoradas, então você pode executar o mesmo arquivo novamente.
* A pessoa que iniciou a importação recebe um e-mail quando ela termina ou é interrompida.

O arquivo enviado é armazenado com criptografia. Ele é excluído quando a importação termina, quando a simulação falha ou 24 horas após uma simulação que nunca foi importada.

## Importar em lotes

Envie até 1,000 pessoas por requisição com um `idempotency_key` de até 100 caracteres.

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

* Uma simulação retorna `200` com o resultado e não grava nada.
* Com `dry_run: false`, uma importação bem-sucedida retorna `201`. Um lote com qualquer erro retorna `400` e não importa ninguém.
* Repetir uma requisição já efetivada com a mesma chave retorna o resultado registrado. A mesma chave com conteúdo diferente retorna `400 {"idempotency_key": "different_payload"}`.
* Os parâmetros do Firebase vão em um objeto `firebase`: `{signer_key, salt_separator, rounds, mem_cost}`.
* `GET imports/` lista os lotes efetivados.

## Formato do arquivo

### JSON

Um array de pessoas ou um objeto cujo `users` contém o array.

| Campo | Regra |
| - | - |
| `email` | Obrigatório. |
| `external_id` | Até 255 caracteres. Passa a ser o [`vendor_data`](https://docs.didit.me/pt-br/entities/vendor-data-linking) da pessoa. |
| `email_verified` | `true` ou `false` (também `1`/`0`, `yes`/`no`). |
| `display_name` | Até 200 caracteres. |
| `password_hash`, `password_salt`, `password_algorithm` | Veja as [senhas](#senhas). |
| `totp_secret` | Segredo do autenticador em Base32. |
| `created_at`, `last_signed_in_at` | ISO 8601. Um horário sem fuso é considerado UTC. |
| `social` | Até 8 `{provider, subject, tenant_id}`. `provider` é `google`, `apple`, `github` ou `microsoft`. `tenant_id` é obrigatório apenas para a Microsoft. |
| `organizations` | Até 20 `{slug, name, role}`. `role` é `admin`, `member` (o padrão) ou `billing`. |

### CSV

As mesmas colunas de valor único, mais `google_id`, `apple_id`, `github_id`, `microsoft_id`, `microsoft_tenant_id`, `organization_slug`, `organization_name` e `organization_role`. Uma pessoa em várias organizações ocupa uma linha por organização.

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

Campos ou colunas desconhecidos são erros e nunca são ignorados.

### Duplicatas e contas existentes

* Linhas com o mesmo e-mail se tornam uma única pessoa. Uma linha idêntica é contada como duplicata. Uma linha com mais vínculos, organizações ou um autenticador é mesclada.
* Dois hashes de senha, segredos de autenticador ou funções em uma organização diferentes para uma mesma pessoa são erros. O mesmo vale para um `external_id` ou um subject de um provedor reivindicado por duas pessoas.
* Se já existir uma conta com esse e-mail e ela tiver sido criada por uma importação anterior, a pessoa é ignorada (`already_imported`). Se a pessoa se cadastrou por conta própria, é um erro `identity_conflict`. Uma importação nunca altera uma conta existente.

## Senhas

| Formato | Aceito |
| - | - |
| bcrypt | `$2a$`, `$2b$` ou `$2y$`, custo de 4 a 13. |
| Argon2id | `$argon2id$v=19$...`. Até 64 MiB de memória, produto da memória pelo número de iterações de até 256 MiB, até 8 lanes. |
| Django PBKDF2-SHA256 | `pbkdf2_sha256$...`, de 10.000 a 2.000.000 de iterações. |
| Django scrypt | `scrypt$...`, fator de trabalho até 32.768, tamanho de bloco de 1 a 8, paralelismo de 1 a 5. |
| Firebase scrypt | `password_algorithm: "firebase_scrypt"`, `password_hash` e `password_salt` em base64 para cada pessoa, além de `signer_key`, `salt_separator`, `rounds` (1 a 8) e `mem_cost` (1 a 14) do seu projeto, uma vez por importação. |

Os parâmetros do Firebase são armazenados criptografados, apenas para aquela aplicação. Qualquer outro formato, ou um custo acima desses limites, significa que a pessoa precisa de uma nova senha. Após o primeiro login bem-sucedido de uma pessoa, a Didit armazena a senha dela novamente no próprio formato da Didit.

### Pessoas sem uma senha utilizável

Quando uma pessoa não tem hash, ou tem um hash não suportado, uma tentativa de login com senha recebe a resposta normal de senha incorreta. A Didit também envia a ela por e-mail um link para definir uma nova senha (válido por 30 minutos, no máximo uma vez por dia). Isso acontece apenas quando o e-mail dela está verificado, a conta não está bloqueada e o login com senha está ativado.

No resultado, `reset_required` conta as pessoas sem uma senha utilizável. `reset_emails` conta, entre elas, aquelas com e-mail verificado: só elas podem ser contatadas dessa forma. Pessoas com e-mail não verificado não podem fazer login com senha. Elas ainda podem fazer login com um código por e-mail se você ativar esse método.

## Vínculos sociais, autenticadores e organizações

* **Vínculos sociais** são mantidos para provedores que sua aplicação já configurou, com o client ID atual dela. Em um login subsequente, essas pessoas não precisam de comprovação por e-mail. Os subjects do Google e do GitHub são globais. Os subjects da Apple são por equipe de desenvolvedor e os da Microsoft são por registro de aplicativo, então esses vínculos só correspondem quando sua plataforma anterior usava a mesma equipe ou o mesmo registro. Vínculos com provedores que você não configurou são contados como `social_unavailable` e não são importados.
* **Aplicativos autenticadores** (segredos TOTP: SHA-1, 6 dígitos, 30 segundos) são armazenados criptografados. As pessoas importadas devem usá-los como segundo fator. Elas não recebem códigos de recuperação.
* **Organizações** que ainda não existem são criadas a partir do slug delas.
* **Chaves de acesso** não podem ser importadas. Elas pertencem ao seu domínio de login anterior, então as pessoas adicionam uma nova chave de acesso depois de fazer login com a Didit.

## Resultados

Simulações, lotes e jobs retornam o mesmo `result`:

| Campo | Significado |
| - | - |
| `rows`, `people_total` | Linhas lidas e pessoas distintas. |
| `ready`, `already_imported`, `duplicates`, `merged`, `skipped` | O que acontece com cada pessoa. |
| `passwords` | Contagens por formato: `bcrypt`, `argon2id`, `firebase_scrypt`, `pbkdf2_sha256`, `scrypt`. |
| `reset_required`, `reset_emails`, `unsupported_hashes` | Pessoas que precisam de uma nova senha. |
| `verified_emails` | Pessoas importadas com e-mail verificado. |
| `social_links`, `social_unavailable` | Vínculos mantidos por provedor e vínculos ignorados. |
| `authenticator_apps` | Pessoas com um autenticador importado. |
| `organizations` | `count`, `members` e até cinco `names`. |
| `error_count`, `errors` | Até 100 erros, cada um com um `row` indexado a partir de zero (linha `row + 2` do CSV), um `field` e um código de `error`. |

As respostas nunca contêm hashes de senha, salts, segredos de autenticador nem valores de campos.

| Erro | Significado |
| - | - |
| `file_too_large`, `too_many_rows`, `empty_file` | Acima de 25 MB, acima de 100.000 pessoas ou vazio. |
| `invalid_encoding`, `invalid_json`, `invalid_csv` | O arquivo não pode ser lido. |
| `unknown_column`, `missing_column`, `duplicate_column`, `unknown_field` | O arquivo não corresponde ao formato. |
| `required`, `invalid_field`, `invalid_row` | Um valor está ausente ou é inválido. |
| `identity_conflict` | Uma conta com esse e-mail se cadastrou por conta própria. |
| `social_link_conflict`, `password_conflict`, `authenticator_conflict`, `role_conflict` | Duas linhas de uma mesma pessoa divergem. |
| `too_many_uploads`, `import_running`, `not_startable`, `file_expired` | O job não pode ser iniciado agora. |

## Antes de fazer a migração definitiva

Teste na sua aplicação de sandbox:

* o login com cada formato de senha que você importar,
* o e-mail para definir uma nova senha para uma pessoa sem um hash utilizável,
* o login social e os códigos do autenticador para pessoas importadas,
* a execução do mesmo arquivo duas vezes.

Depois, confira se o `vendor_data` de cada pessoa corresponde ao valor que você usa nas [verificações e transações](https://docs.didit.me/pt-br/authentication/overview.md#mantenha-uma-única-pessoa-entre-os-produtos) dela.


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