Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions world-id/4-0-migration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ Use these dates as the default migration timeline for planning:

- **Phase 1 (Migration):** through **June 1, 2026**
- Upgrade SDKs/contracts, register your RP, and create v4 actions.
- New World App users will have v3 and v4 credentials
- New World ID users will have v3 and v4 credentials
- **Phase 2 (Transition):** **June 1, 2026** to **March 31, 2027**
- New users from this date will only be able to create 4.0 proofs.
- All users migrated to 4.0
- **Phase 3 (v3 Cut-off):** from **April 1, 2027** onward
- v3 Proofs will no longer be generated by World App
- v3 Proofs will no longer be generated by World ID

If your rollout needs more time, extend Phase 2 and move `CD` later.

Expand Down Expand Up @@ -125,7 +125,7 @@ sequenceDiagram
1. **Update SDKs and Contracts:** RPs upgrade SDKs, contracts, and API calls to enable baseline support for the upgraded protocol. This is backwards compatible.
2. **Register in Developer Portal:** RPs generate their new RP registration and relevant actions for the v4 protocol in the Developer Portal.
3. **For long-running actions:**
- RP decides a transition date (`TD`) to start accepting v4 proofs. They specify a minimum `genesis_issued_at = TD` timestamp in the IDKit request with `allow_legacy_proofs: true` as a temporary compatibility mode. This means only users who get their Orb credential (or document credentials) from this point forward can generate v4 proofs. Users who have not upgraded their World App can still issue v3 proofs during this window. RPs should keep track of both nullifiers.
- RP decides a transition date (`TD`) to start accepting v4 proofs. They specify a minimum `genesis_issued_at = TD` timestamp in the IDKit request with `allow_legacy_proofs: true` as a temporary compatibility mode. This means only users who get their Orb credential (or document credentials) from this point forward can generate v4 proofs. Users who have not upgraded their World ID can still issue v3 proofs during this window. RPs should keep track of both nullifiers.
- At a future cut-off date (`CD > TD`), the RP should switch their IDKit request to `allow_legacy_proofs: false` to stop accepting v3 proofs and only accept v4 proofs.
4. **For limited-time actions** (for example, recurring grant drops): The transition can be made at the action level. Short-running actions have a simpler migration path.

Expand Down
18 changes: 9 additions & 9 deletions world-id/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: world-id-integration
description: |
Use this skill when adding, upgrading, debugging, or testing World ID verification with IDKit in a new or existing web or mobile app. Covers Proof of Human, passport/document, Face Check, and session/sign-in flows; Developer Portal app, RP, and action setup; server-side signing and proof verification; environment matching; nullifier replay protection; and launch testing. Trigger when the user asks to add World ID, verify humans, stop bots or multi-accounting, add Sybil resistance, or mentions IDKit, Orb, World App proof flows, @worldcoin/idkit, signing keys, rp_id, or app_id.
Use this skill when adding, upgrading, debugging, or testing World ID verification with IDKit in a new or existing web or mobile app. Covers Proof of Human, passport/document, Face Check, and session/sign-in flows; Developer Portal app, RP, and action setup; server-side signing and proof verification; environment matching; nullifier replay protection; and launch testing. Trigger when the user asks to add World ID, verify humans, stop bots or multi-accounting, add Sybil resistance, or mentions IDKit, Orb, World ID proof flows, World App proof flows, @worldcoin/idkit, signing keys, rp_id, or app_id.
version: 0.1.0
metadata:
author: worldcoin
Expand Down Expand Up @@ -35,7 +35,7 @@ Before changing code or creating Portal resources:
- integration goal and credential preset
- new or existing project; client, backend, package manager, and persistence layer
- Developer Portal account/team, `app_id`, `rp_id`, and action
- target environment and test path: staging simulator, production World App, or both
- target environment and test path: staging simulator, production World ID, or both
- Developer Portal MCP connection
- whether an RP signing key already exists in a server-side secret store
- credential access, especially Face Check
Expand Down Expand Up @@ -144,25 +144,25 @@ The full code for each step is at [https://docs.world.org/world-id/idkit/integra
1. **Install IDKit** — `^4.x`, the right package for the platform (table in Phase 2).
2. **Create or reuse the Portal resources.** Use the MCP when available. Reuse an existing app, RP, and action when they match the requested integration. For a new RP, capture `app_id`, `rp_id`, and `signing_key.private_key` from `configure_world_id`, create the action in the intended environment, and write the signing key to the prepared server-only secret store in the same step. The portal returns it exactly once. **Do not print, log, or return the private key to chat.** If the key is lost, explain that `get_world_id_signing_key` cannot recover it; rotation creates a new key and invalidates the old signer.
3. **Generate the RP signature in your backend.** *Why backend?* The signing key authenticates your app to the protocol. Leaking it lets anyone impersonate your app and forge proof requests. **CRITICAL: never sign on the client. Never expose `RP_SIGNING_KEY` as a `NEXT_PUBLIC_*` var. Never log it.**
4. **Open the IDKit widget on the client** with the signature your backend returned. The widget hands off to the World App, which produces a zero-knowledge proof.
4. **Open the IDKit widget on the client** with the signature your backend returned. The widget hands off to World ID, which produces a zero-knowledge proof.
5. **Verify the proof in your backend** by POSTing it **as-is** to `https://developer.world.org/api/v4/verify/{rp_id}`. *Why backend?* A client can return any JSON it wants. Only the World verifier — called from a trusted server — confirms the proof is real and tied to a unique credential. Verifying client-side defeats the entire point. **DO NOT mutate, re-encode, or trim the proof JSON before forwarding** — pass exactly what IDKit returned.
6. **Store the nullifier.** Every successful proof returns a `nullifier` — an RP-scoped, action-scoped, non-reversible identifier for that user. *Why store it?* Without uniqueness storage, a user can verify the same proof twice and double-claim a reward, vote, etc. Persist `(action, nullifier)` with a `UNIQUE` constraint and reject duplicates on insert. Column type: **`NUMERIC(78, 0)`** (256-bit field elements). The nullifier reveals nothing about the user — it's safe to store, but it's the *only* anti-replay mechanism, so it's required.

## Phase 5 — Match environments end-to-end

- The **production** World App only signs **production** proofs.
- A **staging** action only verifies against the World App **simulator** ([https://simulator.worldcoin.org](https://simulator.worldcoin.org)).
- The **production** World ID app only signs **production** proofs.
- A **staging** action only verifies against the World ID **Simulator** ([https://simulator.worldcoin.org](https://simulator.worldcoin.org)).
- The IDKit `environment` prop, the action's `environment`, and the simulator-vs-real-app choice **must all match.**

**CRITICAL: if real users will scan with their phones, the action environment must be `production`.** A staging action with the production World App will silently produce zero proofs and look like a frontend bug. If the user needs both simulator testing and real-device QA, create separate staging and production actions.
**CRITICAL: if real users will scan with their phones, the action environment must be `production`.** A staging action with the production World ID app will silently produce zero proofs and look like a frontend bug. If the user needs both simulator testing and real-device QA, create separate staging and production actions.

## Phase 6 — Test the integration end-to-end

Do not declare the integration complete from compilation or Portal configuration alone. Test the selected path and record evidence:

- [ ] RP-signing endpoint succeeds without exposing or logging secrets.
- [ ] Widget/request opens in the selected environment.
- [ ] The selected credential completes with the staging simulator or production World App as intended.
- [ ] The selected credential completes with the staging simulator or production World ID as intended.
- [ ] Backend verification succeeds and the exact IDKit result reaches `/api/v4/verify/{rp_id}`.
- [ ] The verified nullifier is persisted.
- [ ] Replaying the same nullifier is rejected by the database uniqueness constraint.
Expand All @@ -180,7 +180,7 @@ Surface these proactively when you see the corresponding symptom — don't make
| Symptom | Cause | Recovery |
|---|---|---|
| Face Check appears unresponsive or never starts | The app may not be enabled for Face Check | Read `enable_face_check` through MCP when available or `/api/v1/precheck/{app_id}`. If false, stop and explain how to request access. |
| World App shows "action not found" or QR scan does nothing | Action wasn't created in the environment IDKit is pointing at | Create the missing action with `create_world_id_action` (`environment: "production"` for real devices, `"staging"` for simulator). Confirm `NEXT_PUBLIC_WLD_ENVIRONMENT` matches. |
| World ID shows "action not found" or QR scan does nothing | Action wasn't created in the environment IDKit is pointing at | Create the missing action with `create_world_id_action` (`environment: "production"` for real devices, `"staging"` for simulator). Confirm `NEXT_PUBLIC_WLD_ENVIRONMENT` matches. |
| `/api/v4/verify/{rp_id}` returns `invalid_proof` or `verification_failed` | Often staging/production env mismatch, or proof was mutated before forward | Re-check Phase 5. Forward the proof JSON byte-for-byte without re-encoding fields. |
| Verification fails in JS/React and the error code alone isn't enough | Need transport/payload diagnostics | Read `getDebugReport()` (or the `onError` `debugReport` arg) — it carries `transport`, `request_id`, request/response payloads, and World App `mini_app` channel info. JS SDKs only. |
| `/api/v4/verify/{rp_id}` returns `not_registered` or 4xx with `rp` errors | On-chain registration is still `pending` | Poll `get_world_id_registration_status` until the intended environment is `registered`. Production must be registered before launch. |
Expand Down Expand Up @@ -220,7 +220,7 @@ For launch readiness, also confirm:
- Error codes: [https://docs.world.org/world-id/idkit/error-codes](https://docs.world.org/world-id/idkit/error-codes)
- Developer Portal MCP: [https://github.com/worldcoin/developer-portal/tree/main/web/api/mcp](https://github.com/worldcoin/developer-portal/tree/main/web/api/mcp)
- Developer Portal: [https://developer.world.org](https://developer.world.org)
- World App simulator (staging only): [https://simulator.worldcoin.org](https://simulator.worldcoin.org)
- World ID Simulator (staging only): [https://simulator.worldcoin.org](https://simulator.worldcoin.org)

---

Expand Down
6 changes: 3 additions & 3 deletions world-id/credentials/11.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ Selfie Check (Beta) is useful for:

You will need to use IDKit to integrate Selfie Check (Beta) into your application.

* **On Mobile (iOS/Android):** You will use IDKit to generate a Deep Link and attach it to a "Verify" CTA in your app. When the user clicks on this CTA, they are automatically redirected to the World App to complete the Selfie Check (Beta) flow.
* **On Desktop:** You will use IDKit to generate a **QR Code** and display it to the user to complete verification. When the user scans the QR Code with their mobile device camera, World App will launch and guide them through completing the Selfie Check (Beta) flow.
* **On Mobile (iOS/Android):** You will use IDKit to generate a Deep Link and attach it to a "Verify" CTA in your app. When the user clicks on this CTA, they are automatically redirected to World ID to complete the Selfie Check (Beta) flow.
* **On Desktop:** You will use IDKit to generate a **QR Code** and display it to the user to complete verification. When the user scans the QR Code with their mobile device camera, World ID will launch and guide them through completing the Selfie Check (Beta) flow.

## User Experience Flow

1. **Challenge:** The user initiates the flow on your app (Relying Party).
2. **Hand-off:** User is redirected to the World App. If the user doesn’t have the World App installed, they will be dropped into a seamless flow to download the World App and directly go into the Selfie Check (Beta) experience.
2. **Hand-off:** User is redirected to World ID. If the user doesn’t have World ID installed, they will be dropped into a seamless flow to download World ID and directly go into the Selfie Check (Beta) experience.
3. **Enrollment/Auth:**
* **New User:** Prompts to "Take a selfie". The system performs a liveness check and a uniqueness check against other faces.
* **Returning User:** Performs a quick Face Auth to verify continuity.
Expand Down
2 changes: 1 addition & 1 deletion world-id/from-idkit-standalone.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ await IDKit.open();
```

With `idkit-core`, fetch an RP signature from your backend, build the request,
render the `connectorURI`, and poll until World App returns a proof.
render the `connectorURI`, and poll until World ID returns a proof.

```ts title="After"
import { IDKit, orbLegacy } from "@worldcoin/idkit-core";
Expand Down
4 changes: 2 additions & 2 deletions world-id/idkit/credentials.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,9 @@ Successful Identity Check responses include `identity_attested` so your backend

## User presence and liveness

To check for user presence and liveness, add the `require_user_presence` flag to your request. This is a request-level flag, not a credential; it asks World App for a fresh liveness check before returning the proof and fails with `user_presence_failed` if the check is not completed.
To check for user presence and liveness, add the `require_user_presence` flag to your request. This is a request-level flag, not a credential; it asks World ID for a fresh liveness check before returning the proof and fails with `user_presence_failed` if the check is not completed.

Depending on the credential requested, World App matches the user's live selfie to the credential image, such as the passport photo or the image captured during Orb verification.
Depending on the credential requested, World ID matches the user's live selfie to the credential image, such as the passport photo or the image captured during Orb verification.

<CodeGroup title="User presence">
```typescript title="JavaScript"
Expand Down
4 changes: 2 additions & 2 deletions world-id/idkit/design-guidelines.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,11 @@ title: "Design Guidelines"
className="w-full h-auto max-w-[600px]"
/>

**Request canceled** - User manually canceled request in World App
**Request canceled** - User manually canceled request in World ID

<img
src="/images/docs/id/design-guidelines/cancel.png"
alt="Request canceled - User manually canceled request in World App"
alt="Request canceled - User manually canceled request in World ID"
width="600"
height="400"
className="w-full h-auto max-w-[600px]"
Expand Down
2 changes: 1 addition & 1 deletion world-id/idkit/error-codes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This page focuses on IDKit SDK and bridge error codes returned during request fl
<tbody>
<tr>
<td className="p-2 align-middle whitespace-nowrap"><code>user_rejected</code></td>
<td className="p-2 align-middle">User cancelled in World App.</td>
<td className="p-2 align-middle">User cancelled in World ID.</td>
<td className="p-2 align-middle">Treat as user cancellation, allow retry.</td>
</tr>
<tr>
Expand Down
10 changes: 5 additions & 5 deletions world-id/idkit/integrate.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ description: "Integrate World ID into your app"

import IDKitResponse from "/snippets/idkit-response.mdx";

IDKit is the SDK for integrating World ID into your app. It handles proof requests, verification flows, and communication with the World App — so your backend receives a cryptographic proof of human, not personal data.
IDKit is the SDK for integrating World ID into your app. It handles proof requests, verification flows, and communication with the World ID app — so your backend receives a cryptographic proof of human, not personal data.

It's available as a React widget for drop-in integration, or as JS, Swift, and Kotlin SDKs for custom flows. To familiarize yourself with the core concepts of World ID, check out this [page](/world-id/concepts).

> Tip: To integrate faster, give your coding agent the [Build with LLMs prompt](/world-id/idkit/build-with-llms) — copy it once, paste into Claude, Cursor, or any AI coding assistant.

## How it works

Your app sends a **proof request** through IDKit, challenging the user to prove something about themselves — such as uniqueness, document possession, or liveness — based on their [credentials](/world-id/overview#credentials). The user's World App generates a zero-knowledge proof without revealing any personal data. Your backend then verifies that proof and stores a **nullifier** (a per-app, per-action identifier) to prevent the same person from verifying twice.
Your app sends a **proof request** through IDKit, challenging the user to prove something about themselves — such as uniqueness, document possession, or liveness — based on their [credentials](/world-id/overview#credentials). The user's World ID app generates a zero-knowledge proof without revealing any personal data. Your backend then verifies that proof and stores a **nullifier** (a per-app, per-action identifier) to prevent the same person from verifying twice.

<img src="/images/docs/idkit-flow.svg" alt="IDKit integration flow" />

There are four components: your **client** (where IDKit runs), your **backend** (which signs requests and verifies proofs), the **World App** (on the user's device), and the **Developer Portal** (which validates proofs on-chain). The steps below walk through each piece.
There are four components: your **client** (where IDKit runs), your **backend** (which signs requests and verifies proofs), the **World ID app** (on the user's device), and the **Developer Portal** (which validates proofs on-chain). The steps below walk through each piece.

# Step 1: Install IDKit

Expand Down Expand Up @@ -128,7 +128,7 @@ func handleRPSignature(w http.ResponseWriter, r *http.Request) {

<Note>
The steps below cover the standard request flow. Depending on whether the user
already has World App and the credential you're requesting, they may be taken
already has World ID and the credential you're requesting, they may be taken
through a different experience. See [Verification flows](/world-id/idkit/verification-flows)
for details.
</Note>
Expand Down Expand Up @@ -373,7 +373,7 @@ sequenceDiagram

Client->>Client: 2. Create IDKit request with RP signature
Client->>User: 3. Show connect URL / QR code
User->>User: 4. Prove uniqueness in World App
User->>User: 4. Prove uniqueness in World ID

User-->>Client: 5. Proof returned via IDKit

Expand Down
2 changes: 1 addition & 1 deletion world-id/idkit/signatures.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: "Spec for generating RP signatures, with pseudocode, SDK examples,

Relying Party (RP) signatures prove that a proof request genuinely comes from your app, preventing impersonation attacks.
Your backend signs every request with the `signing_key` from the [Developer Portal](https://developer.world.org),
and World App verifies the signature before generating a proof. RP signatures are enforced for [World ID 4.0 requests](/world-id/4-0-migration).
and World ID verifies the signature before generating a proof. RP signatures are enforced for [World ID 4.0 requests](/world-id/4-0-migration).

<Warning>
Never expose your signing key to client-side code. If the key leaks, rotate it immediately in the Developer Portal.
Expand Down
Loading
Loading