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

# Verificació d'identitat amb Okta i Auth0

> Delega la verificació d'identitat a Didit des de Okta Identity Engine (BYO IDV) o Auth0, mitjançant OpenID Connect amb Pushed Authorization Requests.

Didit exposa un servidor d'autorització OpenID Connect pensat específicament per a la verificació d'identitat delegada.
Implementa el contracte que espera el marc "bring your own identity verification vendor" (BYO IDV) d'Okta: Pushed Authorization Requests (PAR, RFC 9126), el flux d'autorització amb codi i PKCE, i un token d'ID que porta un objecte `verified_claims` d'OpenID Connect.

Els mateixos endpoints funcionen per a qualsevol part confiant que utilitzi aquest perfil, inclosos les Actions posteriors a l'inici de sessió d'Auth0.

## Endpoints

Tots els endpoints són sota la URL base del pont de verificació d'identitat.

| Entorn | URL base |
| - | - |
| Producció | `https://apx.didit.me/auth/idv` |
| Sandbox | `https://apx.didit.me/auth/idv` |

La producció i el sandbox utilitzen els mateixos endpoints.
L'aplicació associada a les teves credencials de client determina l'entorn.
Utilitza credencials de client separades i un flux de treball que pertanyi a l'aplicació corresponent per a cada entorn.
Consulta [Sandbox i dades de prova](https://docs.didit.me/ca/integration/sandbox-testing.md) per als resultats de verificació simulats.

El document de descobriment a `{base}/.well-known/openid-configuration` els anuncia tots:

| Finalitat | Endpoint |
| - | - |
| Pushed Authorization Request | `POST {base}/par` |
| Autorització | `GET {base}/authorize` |
| Token | `POST {base}/token` |
| JWKS | `GET {base}/jwks` |
| Descobriment | `GET {base}/.well-known/openid-configuration` |

L'autenticació del client utilitza `client_secret_basic` o `client_secret_post`.
El flux d'autorització amb codi requereix PKCE amb `code_challenge_method=S256`.
Els tokens d'ID es signen amb RS256; verifica'ls amb l'endpoint JWKS.

## Flux

1. La part confiant envia la sol·licitud d'autorització a `POST /par`, incloent-hi el desafiament PKCE, `state`, `nonce`, el seu `redirect_uri` registrat, els scopes `openid profile identity_assurance` i els claims que vol verificar.
   Didit retorna un `request_uri` d'un sol ús vàlid durant 60 segons.
2. La part confiant redirigeix el navegador de l'usuari a `GET /authorize?request_uri=...`.
   Didit crea una sessió de verificació i envia l'usuari al flux de verificació allotjat.
3. Quan l'usuari acaba, Didit avalua la decisió de verificació, compara la identitat extreta amb els claims enviats i retorna l'usuari al `redirect_uri` de la part confiant amb un `code` d'un sol ús i el `state` original.
4. La part confiant intercanvia el code a `POST /token` amb el seu `code_verifier` i rep un token d'ID signat.

## Sol·licitud de claims

Envia els claims a comparar dins del paràmetre `claims` estàndard d'OpenID Connect de la sol·licitud PAR.
Són compatibles `given_name` i `family_name`, i sempre es comparen de manera aproximada.
`verified_claims` és una matriu, d'acord amb el perfil BYO IDV d'Okta i la resposta del token d'ID següent.

```json theme={null}
{
  "id_token": {
    "verified_claims": [
      {
        "verification": {
          "trust_framework": { "value": "IDV-DELEGATED" },
          "assurance_level": { "value": "VERIFIED" }
        },
        "claims": {
          "given_name": { "value": "Lucas", "fuzzy": true },
          "family_name": { "value": "Fraggioli", "fuzzy": true }
        }
      }
    ]
  }
}
```

## El token d'ID

El token d'ID porta una matriu `verified_claims`. `assurance_level` és `VERIFIED` només quan la sessió de verificació ha estat aprovada **i** tots els claims sol·licitats coincideixen amb el document verificat.
En cas contrari, és `FAILED`.

```json theme={null}
{
  "iss": "https://apx.didit.me/auth/idv",
  "sub": "eea9c5ca-63e6-437b-8e94-131c33f5dce8",
  "aud": "<your client id>",
  "nonce": "<your nonce>",
  "verified_claims": [
    {
      "verification": {
        "trust_framework": "IDV-DELEGATED",
        "assurance_level": "VERIFIED",
        "time": "2026-07-09T11:59:33Z",
        "verification_process": "eea9c5ca-63e6-437b-8e94-131c33f5dce8"
      },
      "claims": {
        "given_name": { "value": "Lucas Agustin", "fuzzy": true },
        "family_name": { "value": "Fraggioli", "fuzzy": true }
      }
    }
  ]
}
```

`verification_process` és l'id de la sessió de Didit, de manera que pots consultar la verificació a la consola o a través de l'API de sessions.

> [!NOTE]
>
> Considera l'usuari verificat només quan `trust_framework` és `IDV-DELEGATED` **i** `assurance_level` és `VERIFIED`.
> Qualsevol altra combinació significa que la verificació no s'ha completat amb èxit.

## Configurar Okta

Demana a Didit que activi la verificació d'identitat per a les teves aplicacions de producció i sandbox, que associï cadascuna amb el seu flux de treball de verificació i que registri la URL de callback exacta per a cada tenant d'Okta.
Una aplicació o una clau d'API existents no activen per si soles aquesta integració.

A la consola d'administració d'Okta, afegeix un proveïdor personalitzat de verificació d'identitat i omple els valors següents.
Okta crea la integració com a proveïdor d'identitat de tipus `IDV_STANDARD` amb el protocol `ID_PROOFING`, i després la referencies des d'una regla de la política de gestió de comptes.

| Camp | Valor |
| - | - |
| Issuer | `https://apx.didit.me/auth/idv` |
| URL de la sol·licitud PAR | `https://apx.didit.me/auth/idv/par` |
| URL d'autorització | `https://apx.didit.me/auth/idv/authorize` |
| URL del token | `https://apx.didit.me/auth/idv/token` |
| URL de JWKS | `https://apx.didit.me/auth/idv/jwks` |
| Scopes | `openid`, `profile`, `identity_assurance` |
| Client ID | El client ID de l'aplicació corresponent de Didit |
| Client secret | La clau d'API primària d'aquesta aplicació, disponible a **Developers > API keys** a la Didit Console |

Configura la producció i el sandbox com a integracions de verificació d'identitat separades, amb les seves credencials respectives.
Utilitza els endpoints anteriors per a totes dues.
El client secret és obligatori encara que el flux també utilitzi PKCE.
Una clau d'API amb nom creada per separat no pot substituir la clau d'API primària de l'aplicació en aquesta integració.

Passa a Didit la teva URL de callback perquè es pugui registrar al teu client.
Okta la construeix com `{yourOktaOrgUrl}/idp/identity-verification/callback`.

## Configurar Auth0

Auth0 no té una ranura nativa per a proveïdors de verificació d'identitat, de manera que la verificació s'executa des d'un Action post-login que redirigeix l'usuari al mateix flux.
Desa `DIDIT_IDV_BASE`, `DIDIT_CLIENT_ID` i `DIDIT_CLIENT_SECRET` com a secrets de l'Action, i registra `https://{yourAuth0Domain}/continue` com a redirect URI a Didit.

> [!NOTE]
>
> Auth0 afegeix el seu propi `state` a la redirecció cap a `/authorize` perquè pugui reprendre l'inici de sessió. Didit adopta aquest `state` i el retorna a `/continue`, cosa que permet a Auth0 completar la transacció. No has de passar l'state d'Auth0 pel cos de la PAR (no es genera fins a la redirecció).

```javascript theme={null}
const crypto = require("crypto");

// Correlate each login's PKCE verifier with its own transaction so a retried
// or overlapping login can't overwrite it (which would fail the token exchange).
const txKey = (event) =>
  event.transaction?.id || event.request?.query?.state || "default";

const basicAuth = (event) =>
  Buffer.from(
    `${event.secrets.DIDIT_CLIENT_ID}:${event.secrets.DIDIT_CLIENT_SECRET}`
  ).toString("base64");

exports.onExecutePostLogin = async (event, api) => {
  if (event.user.app_metadata?.idv_status === "verified") return;

  const verifier = crypto.randomBytes(48).toString("base64url");
  const challenge = crypto.createHash("sha256").update(verifier).digest("base64url");

  const pending = { ...event.user.app_metadata?.idv_pkce };
  pending[txKey(event)] = verifier;
  api.user.setAppMetadata("idv_pkce", pending);

  const params = {
    response_type: "code",
    client_id: event.secrets.DIDIT_CLIENT_ID,
    redirect_uri: `https://${event.request.hostname}/continue`,
    scope: "openid profile identity_assurance",
    code_challenge: challenge,
    code_challenge_method: "S256",
    login_hint: event.user.email ?? "",
  };

  // Ask Didit to match the scanned document against this user's known name, so an
  // approved session for a different person can't mark this account verified.
  if (event.user.given_name && event.user.family_name) {
    params.claims = JSON.stringify({
      id_token: {
        verified_claims: [
          {
            verification: { trust_framework: { value: "IDV-DELEGATED" } },
            claims: {
              given_name: { value: event.user.given_name, fuzzy: true },
              family_name: { value: event.user.family_name, fuzzy: true },
            },
          },
        ],
      },
    });
  }

  const res = await fetch(`${event.secrets.DIDIT_IDV_BASE}/par`, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
      Authorization: `Basic ${basicAuth(event)}`,
    },
    body: new URLSearchParams(params).toString(),
  });
  if (!res.ok) return api.access.deny("Identity verification is unavailable.");

  const { request_uri } = await res.json();
  api.redirect.sendUserTo(`${event.secrets.DIDIT_IDV_BASE}/authorize`, {
    query: { request_uri, client_id: event.secrets.DIDIT_CLIENT_ID },
  });
};

exports.onContinuePostLogin = async (event, api) => {
  const code = event.request.query.code;
  const pending = { ...event.user.app_metadata?.idv_pkce };
  const key = txKey(event);
  const verifier = pending[key];

  // Consume the verifier so it can't be reused.
  if (key in pending) {
    delete pending[key];
    api.user.setAppMetadata("idv_pkce", pending);
  }
  if (!code || !verifier) return api.access.deny("Identity verification was not completed.");

  const res = await fetch(`${event.secrets.DIDIT_IDV_BASE}/token`, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
      Authorization: `Basic ${basicAuth(event)}`,
    },
    body: new URLSearchParams({
      grant_type: "authorization_code",
      code,
      code_verifier: verifier,
      redirect_uri: `https://${event.request.hostname}/continue`,
    }).toString(),
  });
  if (!res.ok) return api.access.deny("Identity verification could not be confirmed.");

  const { id_token } = await res.json();
  // This token comes directly from Didit's token endpoint over TLS with client
  // authentication (the trusted back-channel), so decoding is sufficient here.
  // For defense-in-depth, verify the RS256 signature against the JWKS endpoint
  // (plus iss / aud / exp / nonce) before trusting it.
  const payload = JSON.parse(Buffer.from(id_token.split(".")[1], "base64url").toString());
  const verification = payload.verified_claims?.[0]?.verification ?? {};

  if (verification.trust_framework === "IDV-DELEGATED" && verification.assurance_level === "VERIFIED") {
    api.user.setAppMetadata("idv_status", "verified");
    api.user.setAppMetadata("idv_session", verification.verification_process ?? null);
  } else {
    api.access.deny("Identity verification failed.");
  }
};
```

> [!NOTE]
>
> Desa el `code_verifier` de PKCE per cada transacció d'inici de sessió (indexat per `event.transaction.id`), no en un únic camp de `app_metadata`.
> Si un usuari torna a intentar-ho o hi ha un inici de sessió simultani, un camp compartit es sobreescriu i l'intercanvi del token falla amb `invalid_grant`.

## Errors

Els errors segueixen les especificacions RFC 6749 i RFC 9126.
Una autenticació de client fallida retorna `401` amb `{"error": "invalid_client"}`; un `request_uri` o un codi d'autorització caducat o reutilitzat retorna `400` amb `invalid_request` o `invalid_grant`.

Els codis d'autorització, els valors de `request_uri` i les sessions de verificació són tots d'un sol ús.


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