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

# Okta और Auth0 पहचान सत्यापन

> Didit से पहचान सत्यापन को Okta Identity Engine (BYO IDV) या Auth0 में सौंपें, OpenID Connect और Pushed Authorization Requests के साथ।

Didit एक OpenID Connect authorization server उपलब्ध कराता है, जिसे विशेष रूप से सौंपे गए पहचान सत्यापन (delegated identity verification) के लिए बनाया गया है।
यह वह अनुबंध लागू करता है जिसकी Okta का "bring your own identity verification vendor" (BYO IDV) framework अपेक्षा करता है: Pushed Authorization Requests (PAR, RFC 9126), PKCE के साथ authorization code flow, और एक ID token जिसमें OpenID Connect `verified_claims` object होता है।

यही endpoints किसी भी relying party के लिए काम करते हैं जो इस profile का पालन करता है, जिसमें Auth0 post-login Actions भी शामिल हैं।

## Endpoints

हर endpoint पहचान सत्यापन ब्रिज के base URL के अंतर्गत आता है।

| एनवायरनमेंट | बेस URL |
| - | - |
| प्रोडक्शन | `https://apx.didit.me/auth/idv` |
| सैंडबॉक्स | `https://apx.didit.me/auth/idv` |

प्रोडक्शन और सैंडबॉक्स के लिए एक ही endpoints इस्तेमाल होते हैं।
आपके client credentials से जुड़ा एप्लिकेशन तय करता है कि कौन-सा एनवायरनमेंट इस्तेमाल होगा।
हर एनवायरनमेंट के लिए अलग client credentials और संबंधित एप्लिकेशन से जुड़ा वर्कफ़्लो इस्तेमाल करें।
सिम्युलेटेड सत्यापन परिणामों के लिए [Sandbox & Test Data](https://docs.didit.me/hi/integration/sandbox-testing.md) देखें।

`{base}/.well-known/openid-configuration` पर मौजूद discovery document इन सभी endpoints की जानकारी देता है:

| उद्देश्य | Endpoint |
| - | - |
| Pushed Authorization Request | `POST {base}/par` |
| Authorization | `GET {base}/authorize` |
| Token | `POST {base}/token` |
| JWKS | `GET {base}/jwks` |
| Discovery | `GET {base}/.well-known/openid-configuration` |

Client authentication के लिए `client_secret_basic` या `client_secret_post` इस्तेमाल होता है।
Authorization code flow में PKCE अनिवार्य है, जिसमें `code_challenge_method=S256` होना चाहिए।
ID tokens RS256 से हस्ताक्षरित होते हैं; इन्हें JWKS endpoint से सत्यापित करें।

## प्रवाह

1. Relying party `POST /par` पर authorization request push करती है, जिसमें PKCE challenge, `state`, `nonce`, उसका पंजीकृत `redirect_uri`, scopes `openid profile identity_assurance`, और वे claims शामिल होते हैं जिनका सत्यापन चाहिए।
   Didit एक single-use `request_uri` लौटाता है, जो 60 सेकंड के लिए वैध है।
2. Relying party उपयोगकर्ता के browser को `GET /authorize?request_uri=...` पर redirect करती है।
   Didit एक verification सत्र बनाता है और उपयोगकर्ता को hosted verification flow में भेजता है।
3. जब उपयोगकर्ता प्रक्रिया पूरी कर लेता है, तब Didit verification decision का मूल्यांकन करता है, निकाली गई पहचान की तुलना push किए गए claims से करता है, और उपयोगकर्ता को relying party के `redirect_uri` पर वापस भेजता है, साथ में एक वन-टाइम `code` और मूल `state`।
4. Relying party `POST /token` पर अपने `code_verifier` के साथ code का आदान-प्रदान करती है और एक signed ID token प्राप्त करती है।

## क्लेम का अनुरोध

तुलना किए जाने वाले claims को PAR अनुरोध में standard OpenID Connect `claims` parameter के अंदर भेजें।
`given_name` और `family_name` दोनों समर्थित हैं, और दोनों की हमेशा fuzzy तुलना होती है।
`verified_claims` एक array है, जो Okta के BYO IDV profile और नीचे दिए ID token response से मेल खाता है।

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

## ID टोकन

ID token में `verified_claims` array होता है।
`assurance_level` केवल तभी `VERIFIED` होता है जब verification सत्र स्वीकृत हुआ **और** माँगा गया हर claim सत्यापित दस्तावेज़ से मेल खाया।
अन्यथा यह `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` Didit सत्र id है, ताकि आप verification को console में या sessions API के माध्यम से खोज सकें।

> [!NOTE]
>
> उपयोगकर्ता को तभी verified मानें जब `trust_framework` `IDV-DELEGATED` हो **और** `assurance_level` `VERIFIED` हो।
> कोई भी अन्य संयोजन बताता है कि verification सफल नहीं हुआ।

## Okta कॉन्फ़िगर करें

Didit से अनुरोध करें कि आपके production और sandbox एप्लिकेशनों के लिए identity verification सक्षम करे, हर एप्लिकेशन को उसके verification वर्कफ़्लो से जोड़े, और हर Okta tenant के लिए सटीक callback URL पंजीकृत करे।
अकेला मौजूदा एप्लिकेशन या API कुंजी इस integration को सक्षम नहीं करता।

Okta Admin Console में एक custom identity verification vendor जोड़ें और नीचे दिए मान भरें।
Okta इस integration को `IDV_STANDARD` type और `ID_PROOFING` protocol वाले identity provider के रूप में बनाता है, और फिर आप इसे Account Management Policy rule से संदर्भित करते हैं।

| फ़ील्ड | मान |
| - | - |
| Issuer | `https://apx.didit.me/auth/idv` |
| PAR request URL | `https://apx.didit.me/auth/idv/par` |
| Authorize URL | `https://apx.didit.me/auth/idv/authorize` |
| Token URL | `https://apx.didit.me/auth/idv/token` |
| JWKS URL | `https://apx.didit.me/auth/idv/jwks` |
| Scopes | `openid`, `profile`, `identity_assurance` |
| Client ID | संबंधित Didit एप्लिकेशन का client ID |
| Client secret | उस एप्लिकेशन की प्राथमिक API कुंजी, जो Didit Console में **Developers > API keys** के अंतर्गत उपलब्ध है |

Production और sandbox को अलग-अलग identity verification integrations के रूप में, उनके संबंधित credentials के साथ कॉन्फ़िगर करें।
दोनों के लिए ऊपर दिए endpoints इस्तेमाल करें।
PKCE इस्तेमाल होने के बावजूद client secret आवश्यक है।
इस integration के लिए अलग से बनाई गई नामित API कुंजी एप्लिकेशन की प्राथमिक API कुंजी की जगह नहीं ले सकती।

अपना कॉलबैक URL Didit को दें, ताकि उसे आपके client पर पंजीकृत किया जा सके।
Okta इसे `{yourOktaOrgUrl}/idp/identity-verification/callback` के रूप में बनाता है।

## Auth0 कॉन्फ़िगर करें

Auth0 में कोई native IDV vendor slot नहीं है, इसलिए verification एक post-login Action से चलता है, जो उपयोगकर्ता को उसी flow में redirect करती है।
`DIDIT_IDV_BASE`, `DIDIT_CLIENT_ID` और `DIDIT_CLIENT_SECRET` को Action secrets के रूप में सहेजें, और `https://{yourAuth0Domain}/continue` को Didit के साथ redirect URI के रूप में पंजीकृत करें।

> [!NOTE]
>
> Auth0 login जारी रखने के लिए `/authorize` redirect में अपना `state` जोड़ता है।
> Didit उस `state` को अपनाता है और `/continue` पर वापस भेजता है, जिससे Auth0 लेन-देन पूरा कर पाता है - आपको Auth0 का state PAR body में नहीं डालना होता (वह redirect तक उत्पन्न नहीं होता)।

```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]
>
> PKCE `code_verifier` को हर login लेन-देन के हिसाब से सहेजें (`event.transaction.id` को कुंजी के रूप में इस्तेमाल करके), एक ही `app_metadata` फ़ील्ड में नहीं।
> अगर उपयोगकर्ता पुनः प्रयास करता है या एक साथ चलने वाला लॉगिन चलाता है, तो एक साझा फ़ील्ड पर नया मान लिख दिया जाता है और token का आदान-प्रदान `invalid_grant` के साथ विफल हो जाता है।

## त्रुटियाँ

त्रुटियाँ RFC 6749 और RFC 9126 का पालन करती हैं।
विफल क्लाइंट प्रमाणीकरण `401` लौटाता है, जिसके साथ `{"error": "invalid_client"}` आता है। समय-सीमा समाप्त या दोबारा भेजे गए `request_uri` या प्राधिकरण कोड पर `400` लौटता है, जिसके साथ `invalid_request` या `invalid_grant` आता है।

प्राधिकरण कोड, `request_uri` मान और सत्यापन सत्र, इन सभी का उपयोग केवल एक बार किया जा सकता है।


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