From c573d82f86e4b8e21d894220fb4c591d381098d6 Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 16:21:34 -0700 Subject: [PATCH 01/21] first readme change --- js/packages/core/README.md | 115 +++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index 494f4d1f..b2208862 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -8,6 +8,121 @@ World ID verification SDK for JavaScript/TypeScript. Zero dependencies, WASM-pow npm install @worldcoin/idkit-core ``` +## Quickstart + +World ID 4.0 has two kinds of verification flows. Pick the one that matches your use case — both can be dropped into an HTML page with the CDN build below. + +| Flow | Entry point | Use it when | `action` field | +| --- | --- | --- | --- | +| **Action proof** | `IDKit.request()` | One-time check scoped to a specific action (e.g. `claim-airdrop-2026`). The action scopes the nullifier, so your backend can detect double-claims. | Required | +| **Session proof** | `IDKit.createSession()` / `IDKit.proveSession()` | Returning-user continuity. The user proves they're the same person across visits without redoing a full verification each time. You get back a `session_id` to save and reuse. | Not accepted — sessions are scoped to your app via `rp_context` | + +Both flows let you configure the credential level the same way, via `.constraints(...)` (a tree of `CredentialRequest(...)` combined with `any` / `all` / `enumerate`). Action proofs also accept `.preset(...)` for common scenarios — see [Using Presets](#using-presets). + +### Action proof on an HTML page + +```html + + +``` + +### Session proof on an HTML page + +`createSession` returns a `session_id` on success — save it server-side as the stable identifier for that user. On return visits, call `proveSession` with the saved ID; the response's `session_id` will match for the same user. + +```html + + +``` + ## Script Tag / CDN The package also publishes a browser global build at From 7f307537b4d61a1ed72d46501c5278cb822fac68 Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 16:24:03 -0700 Subject: [PATCH 02/21] cleanup --- js/packages/core/README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index b2208862..060b2fb2 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -12,12 +12,9 @@ npm install @worldcoin/idkit-core World ID 4.0 has two kinds of verification flows. Pick the one that matches your use case — both can be dropped into an HTML page with the CDN build below. -| Flow | Entry point | Use it when | `action` field | -| --- | --- | --- | --- | -| **Action proof** | `IDKit.request()` | One-time check scoped to a specific action (e.g. `claim-airdrop-2026`). The action scopes the nullifier, so your backend can detect double-claims. | Required | -| **Session proof** | `IDKit.createSession()` / `IDKit.proveSession()` | Returning-user continuity. The user proves they're the same person across visits without redoing a full verification each time. You get back a `session_id` to save and reuse. | Not accepted — sessions are scoped to your app via `rp_context` | +| **Action proof** | `IDKit.request()` +| **Session proof** | `IDKit.createSession()` / `IDKit.proveSession()` -Both flows let you configure the credential level the same way, via `.constraints(...)` (a tree of `CredentialRequest(...)` combined with `any` / `all` / `enumerate`). Action proofs also accept `.preset(...)` for common scenarios — see [Using Presets](#using-presets). ### Action proof on an HTML page From 64df70332962e1befd162683977127a828076e22 Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 16:31:31 -0700 Subject: [PATCH 03/21] removed table format shortened explanation --- js/packages/core/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index 060b2fb2..035f57e9 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -10,11 +10,12 @@ npm install @worldcoin/idkit-core ## Quickstart -World ID 4.0 has two kinds of verification flows. Pick the one that matches your use case — both can be dropped into an HTML page with the CDN build below. +`IDKit.request()` builds a nullifier- and action-backed proof request. `IDKit.createSession()` / `IDKit.proveSession()` work with **session proofs** — a new concept in IDKit 4.0 with no action backing; they return a `session_id` that you track on its own as the stable identifier for that user. -| **Action proof** | `IDKit.request()` -| **Session proof** | `IDKit.createSession()` / `IDKit.proveSession()` +- **Action proof** — `IDKit.request()`. Requires an `action`. Returns a one-time-use `nullifier` scoped to that action; your backend dedups on it to prevent double-claims. +- **Session proof** — `IDKit.createSession()` (first time) / `IDKit.proveSession(sessionId, ...)` (returning). No `action` field. Returns a stable `session_id` (per user-per-app) that you store as the long-lived identifier, plus a one-time-use `session_nullifier` per proof for replay protection. +Both flows configure credentials the same way via `.constraints(...)` (a tree of `CredentialRequest(...)` combined with `any` / `all` / `enumerate`). Action proofs also accept `.preset(...)` for common scenarios — see [Using Presets](#using-presets). ### Action proof on an HTML page From c021f03150c169ab51a9ece7cf45f1b58086862e Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 17:59:20 -0700 Subject: [PATCH 04/21] cleaniup --- js/packages/core/README.md | 128 ++++++++----------------------------- 1 file changed, 28 insertions(+), 100 deletions(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index 035f57e9..dc42da12 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -10,115 +10,43 @@ npm install @worldcoin/idkit-core ## Quickstart -`IDKit.request()` builds a nullifier- and action-backed proof request. `IDKit.createSession()` / `IDKit.proveSession()` work with **session proofs** — a new concept in IDKit 4.0 with no action backing; they return a `session_id` that you track on its own as the stable identifier for that user. +There are two ways you can request proofs with IDKit, and they depend on how you want to use the SDK. -- **Action proof** — `IDKit.request()`. Requires an `action`. Returns a one-time-use `nullifier` scoped to that action; your backend dedups on it to prevent double-claims. -- **Session proof** — `IDKit.createSession()` (first time) / `IDKit.proveSession(sessionId, ...)` (returning). No `action` field. Returns a stable `session_id` (per user-per-app) that you store as the long-lived identifier, plus a one-time-use `session_nullifier` per proof for replay protection. +If you want World ID credentials to be users' main form of login, use `IDKit.createSession()` / `IDKit.proveSession()`: -Both flows configure credentials the same way via `.constraints(...)` (a tree of `CredentialRequest(...)` combined with `any` / `all` / `enumerate`). Action proofs also accept `.preset(...)` for common scenarios — see [Using Presets](#using-presets). - -### Action proof on an HTML page - -```html - - +const provenResult = await proven.pollUntilCompletion(); +// provenResult.result.session_id matches for the same user ``` -### Session proof on an HTML page - -`createSession` returns a `session_id` on success — save it server-side as the stable identifier for that user. On return visits, call `proveSession` with the saved ID; the response's `session_id` will match for the same user. - -```html - - +const completion = await request.pollUntilCompletion(); +// send completion.result to your backend → /api/v4/verify/{rp_id} +// store the nullifier; same person + same action = reject on return ``` ## Script Tag / CDN From a8f12c16da52ddb399a36d382c271ed7e49cd31c Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 18:04:17 -0700 Subject: [PATCH 05/21] better comments --- js/packages/core/README.md | 41 ++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index dc42da12..0fe74990 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -16,22 +16,34 @@ If you want World ID credentials to be users' main form of login, use `IDKit.cre ```js // First visit — mint a session_id and store it server-side -const created = await IDKit.createSession({ +const IDKitSessionRequest = await IDKit.createSession({ app_id: "app_xxxxx", rp_context: { /* from your backend */ }, -}).constraints(IDKit.CredentialRequest("proof_of_human")); - -const createdResult = await created.pollUntilCompletion(); -// save createdResult.result.session_id in your DB +}).constraints(IDKit.CredentialRequest("proof_of_human")); // → IDKitRequest + +const result = await IDKitSessionRequest.pollUntilCompletion(); +// → { success: true, result: IDKitResultSession } | { success: false, error } +// IDKitResultSession: { +// protocol_version: "4.0", +// session_id: "session_", +// nonce: string, +// responses: [{ identifier, proof, session_nullifier, ... }], +// environment: string, +// ... +// } +// save result.result.session_id in your DB +``` +```js // Return visit — look up that session_id, then prove it -const proven = await IDKit.proveSession(savedSessionId, { +const IDKitSessionRequest = await IDKit.proveSession(savedSessionId, { app_id: "app_xxxxx", rp_context: { /* from your backend */ }, -}).constraints(IDKit.CredentialRequest("proof_of_human")); +}).constraints(IDKit.CredentialRequest("proof_of_human")); // → IDKitRequest -const provenResult = await proven.pollUntilCompletion(); -// provenResult.result.session_id matches for the same user +const result = await IDKitSessionRequest.pollUntilCompletion(); +// → { success: true, result: IDKitResultSession } | { success: false, error } +// same shape as createSession — result.result.session_id matches for the same user ``` If you want to gate a specific action behind a credential, use `IDKit.request()`: @@ -42,9 +54,18 @@ const request = await IDKit.request({ action: "claim-airdrop-2026", rp_context: { /* from your backend */ }, allow_legacy_proofs: false, -}).constraints(IDKit.CredentialRequest("proof_of_human")); +}).constraints(IDKit.CredentialRequest("proof_of_human")); // → IDKitRequest const completion = await request.pollUntilCompletion(); +// → { success: true, result: IDKitResult } | { success: false, error } +// IDKitResult (v4 uniqueness): { +// protocol_version: "4.0", +// action: string, +// nonce: string, +// responses: [{ identifier, proof, nullifier, ... }], +// environment: string, +// ... +// } // send completion.result to your backend → /api/v4/verify/{rp_id} // store the nullifier; same person + same action = reject on return ``` From 1278c5faac53d722659e2d1210b64ec4048f1b67 Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 18:07:15 -0700 Subject: [PATCH 06/21] modernize the document and shorten redundant parts --- js/packages/core/README.md | 81 ++++---------------------------------- 1 file changed, 8 insertions(+), 73 deletions(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index 0fe74990..3665b46b 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -70,6 +70,8 @@ const completion = await request.pollUntilCompletion(); // store the nullifier; same person + same action = reject on return ``` +Either way: show `request.connectorURI` as a QR, wait for `pollUntilCompletion()`, then send `result` to your backend and forward it to `POST https://developer.worldcoin.org/api/v4/verify/{rp_id}`. Don't trust the client proof until that verify call succeeds. + ## Script Tag / CDN The package also publishes a browser global build at @@ -115,18 +117,18 @@ browser global; generate RP signatures on your backend with ## Backend: Generate RP Signature -The RP signature authenticates your verification requests. Generate it server-side using the `/signing` subpath (pure JS, no WASM init needed): +That `rp_context` in the examples above comes from your backend. Generate it server-side with the `/signing` subpath (pure JS, no WASM init needed): ```typescript import { signRequest } from "@worldcoin/idkit-core/signing"; // Never expose RP_SIGNING_KEY to clients const sig = signRequest({ - action: "my-action", + action: "my-action", // omit for session flows signingKeyHex: process.env.RP_SIGNING_KEY!, }); -// Return to client +// Return to client — this is your rp_context payload res.json({ sig: sig.sig, nonce: sig.nonce, @@ -135,90 +137,23 @@ res.json({ }); ``` -## Client: Create Verification Request +## Using Presets -### Using Presets - -For common verification scenarios with World ID 3.0 backward compatibility: +If you need World ID 3.0 backward compatibility, swap `.constraints(...)` for a legacy preset on `IDKit.request()` (sessions don't support presets): ```typescript import { IDKit, orbLegacy } from "@worldcoin/idkit-core"; -// Fetch signature from your backend -const rpSig = await fetch("/api/rp-signature").then((r) => r.json()); - const request = await IDKit.request({ app_id: "app_xxxxx", action: "my-action", - rp_context: { - rp_id: "rp_xxxxx", - nonce: rpSig.nonce, - created_at: rpSig.created_at, - expires_at: rpSig.expires_at, - signature: rpSig.sig, - }, + rp_context: { /* from your backend */ }, allow_legacy_proofs: false, - return_to: "myapp://idkit/callback", }).preset(orbLegacy({ signal: "user-123" })); - -// Display QR code for World App -const qrUrl = request.connectorURI; ``` **Available presets:** `orbLegacy`, `documentLegacy`, `secureDocumentLegacy`, `deviceLegacy`, `selfieCheckLegacy` -Selfie check preset example: - -```typescript -import { IDKit, selfieCheckLegacy } from "@worldcoin/idkit-core"; - -const request = await IDKit.request({ - app_id: "app_xxxxx", - action: "my-action", - rp_context: rpContext, - allow_legacy_proofs: false, -}).preset(selfieCheckLegacy({ signal: "user-123" })); -``` - -## Handling the Result - -Poll for the verification proof, then verify it server-side: - -```typescript -// Wait for the user to scan and approve -const completion = await request.pollUntilCompletion({ - pollInterval: 2000, - timeout: 120_000, -}); - -if (!completion.success) { - console.error("Verification failed:", completion.error); - return; -} - -// Send proof to your backend for verification -const verified = await fetch("/api/verify-proof", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(completion.result), -}).then((r) => r.json()); -``` - -On your backend, forward the result to the Developer Portal: - -```typescript -const response = await fetch( - `https://developer.worldcoin.org/api/v4/verify/${RP_ID}`, - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(req.body), - }, -); - -const { success } = await response.json(); -``` - ## Subpath Exports Pure JS subpath exports are available for server-side use without WASM initialization: From 5c6ddec247a47b221494e04e55b3c43c61caa30d Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 18:13:04 -0700 Subject: [PATCH 07/21] add imports to first code example --- js/packages/core/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index 3665b46b..52f0ac8c 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -15,6 +15,8 @@ There are two ways you can request proofs with IDKit, and they depend on how you If you want World ID credentials to be users' main form of login, use `IDKit.createSession()` / `IDKit.proveSession()`: ```js +import { IDKit } from "@worldcoin/idkit-core"; + // First visit — mint a session_id and store it server-side const IDKitSessionRequest = await IDKit.createSession({ app_id: "app_xxxxx", @@ -148,7 +150,7 @@ const request = await IDKit.request({ app_id: "app_xxxxx", action: "my-action", rp_context: { /* from your backend */ }, - allow_legacy_proofs: false, + allow_legacy_proofs: true, }).preset(orbLegacy({ signal: "user-123" })); ``` From 74adcd51a490bd267e93c4836a8f2de727f1946e Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 18:15:28 -0700 Subject: [PATCH 08/21] update presets doc --- js/packages/core/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index 52f0ac8c..bdc4a10f 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -154,7 +154,9 @@ const request = await IDKit.request({ }).preset(orbLegacy({ signal: "user-123" })); ``` -**Available presets:** `orbLegacy`, `documentLegacy`, `secureDocumentLegacy`, `deviceLegacy`, `selfieCheckLegacy` +**Available legacy presets** (`allow_legacy_proofs: true`): `orbLegacy`, `documentLegacy`, `secureDocumentLegacy`, `deviceLegacy`, `selfieCheckLegacy` + +If `allow_legacy_proofs` is `false`, available v4.0 presets are: `proofOfHuman`, `passport`, `mnc`, `identityCheck` ## Subpath Exports From 540f508df1e01f43ae2bd2c5f262fdc4209d91bf Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 18:21:41 -0700 Subject: [PATCH 09/21] add result documentation --- js/packages/core/README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index bdc4a10f..ab26bf80 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -72,7 +72,22 @@ const completion = await request.pollUntilCompletion(); // store the nullifier; same person + same action = reject on return ``` -Either way: show `request.connectorURI` as a QR, wait for `pollUntilCompletion()`, then send `result` to your backend and forward it to `POST https://developer.worldcoin.org/api/v4/verify/{rp_id}`. Don't trust the client proof until that verify call succeeds. +### Handling the result + +Show `connectorURI` as a QR while you poll. Once `pollUntilCompletion()` succeeds, send `result` to your backend — don't trust it client-side. Your backend forwards it to the Developer Portal: + +```typescript +const response = await fetch( + `https://developer.world.org/api/v4/verify/${RP_ID}`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(completion.result), // IDKitResult / IDKitResultSession + }, +); + +const { success } = await response.json(); +``` ## Script Tag / CDN From bac65916d4cc77ee7ef742c150be4c631e5cd333 Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 18:22:07 -0700 Subject: [PATCH 10/21] format --- js/packages/core/README.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index ab26bf80..301e2d32 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -20,7 +20,9 @@ import { IDKit } from "@worldcoin/idkit-core"; // First visit — mint a session_id and store it server-side const IDKitSessionRequest = await IDKit.createSession({ app_id: "app_xxxxx", - rp_context: { /* from your backend */ }, + rp_context: { + /* from your backend */ + }, }).constraints(IDKit.CredentialRequest("proof_of_human")); // → IDKitRequest const result = await IDKitSessionRequest.pollUntilCompletion(); @@ -40,7 +42,9 @@ const result = await IDKitSessionRequest.pollUntilCompletion(); // Return visit — look up that session_id, then prove it const IDKitSessionRequest = await IDKit.proveSession(savedSessionId, { app_id: "app_xxxxx", - rp_context: { /* from your backend */ }, + rp_context: { + /* from your backend */ + }, }).constraints(IDKit.CredentialRequest("proof_of_human")); // → IDKitRequest const result = await IDKitSessionRequest.pollUntilCompletion(); @@ -54,7 +58,9 @@ If you want to gate a specific action behind a credential, use `IDKit.request()` const request = await IDKit.request({ app_id: "app_xxxxx", action: "claim-airdrop-2026", - rp_context: { /* from your backend */ }, + rp_context: { + /* from your backend */ + }, allow_legacy_proofs: false, }).constraints(IDKit.CredentialRequest("proof_of_human")); // → IDKitRequest @@ -164,7 +170,9 @@ import { IDKit, orbLegacy } from "@worldcoin/idkit-core"; const request = await IDKit.request({ app_id: "app_xxxxx", action: "my-action", - rp_context: { /* from your backend */ }, + rp_context: { + /* from your backend */ + }, allow_legacy_proofs: true, }).preset(orbLegacy({ signal: "user-123" })); ``` From b6d1c27aff39b03883beeb7c3522b44aac12467f Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 18:23:52 -0700 Subject: [PATCH 11/21] git push --- js/packages/core/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index 301e2d32..a994e35f 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -80,7 +80,7 @@ const completion = await request.pollUntilCompletion(); ### Handling the result -Show `connectorURI` as a QR while you poll. Once `pollUntilCompletion()` succeeds, send `result` to your backend — don't trust it client-side. Your backend forwards it to the Developer Portal: +Result should always be handled in the backend, good practice is to have a `/api/verify` route ```typescript const response = await fetch( From 201763c7f2c9a21832853455b81c513406f004a4 Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 18:29:20 -0700 Subject: [PATCH 12/21] add imports, verify snippet --- js/packages/core/README.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index a994e35f..973f077c 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -80,19 +80,25 @@ const completion = await request.pollUntilCompletion(); ### Handling the result -Result should always be handled in the backend, good practice is to have a `/api/verify` route +Result should always be handled in the backend. A good practice is to have a dedicated `/api/verify` route file where you have some form of the following: ```typescript -const response = await fetch( - `https://developer.world.org/api/v4/verify/${RP_ID}`, - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(completion.result), // IDKitResult / IDKitResultSession - }, -); - -const { success } = await response.json(); +import type { IDKitResult } from "@worldcoin/idkit-core"; + +// proof = completion.result from pollUntilCompletion() +async function verifyProof(proof: IDKitResult, rpId: string) { + const response = await fetch( + `https://developer.world.org/api/v4/verify/${rpId}`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(proof), + }, + ); + + const { success } = await response.json(); + return success; +} ``` ## Script Tag / CDN From d4becb43249182c5260bcd2b2b99df94b649f68d Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 18:41:46 -0700 Subject: [PATCH 13/21] handwrite and check readme --- js/packages/core/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index 973f077c..009f67e5 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -12,7 +12,7 @@ npm install @worldcoin/idkit-core There are two ways you can request proofs with IDKit, and they depend on how you want to use the SDK. -If you want World ID credentials to be users' main form of login, use `IDKit.createSession()` / `IDKit.proveSession()`: +If you want to request World ID proofs one time, with session scope, us `IDKit.createSession()` and store the users' `session_id` from the result. You can then use `IDKit.proveSession` with session_id as a parameter. This is useful if you want to constrain sessions based on time, or refresh the type of credential you request from the user. ```js import { IDKit } from "@worldcoin/idkit-core"; @@ -52,7 +52,7 @@ const result = await IDKitSessionRequest.pollUntilCompletion(); // same shape as createSession — result.result.session_id matches for the same user ``` -If you want to gate a specific action behind a credential, use `IDKit.request()`: +If you want to request a credential based on an action-key scope, use `IDKit.request()' and store the nullifier. ```js const request = await IDKit.request({ From 7c0e5e00b802e11791a05f7af5605b312352f446 Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 18:45:32 -0700 Subject: [PATCH 14/21] tidying first part --- js/packages/core/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index 009f67e5..22046565 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -12,7 +12,7 @@ npm install @worldcoin/idkit-core There are two ways you can request proofs with IDKit, and they depend on how you want to use the SDK. -If you want to request World ID proofs one time, with session scope, us `IDKit.createSession()` and store the users' `session_id` from the result. You can then use `IDKit.proveSession` with session_id as a parameter. This is useful if you want to constrain sessions based on time, or refresh the type of credential you request from the user. +If you want to request a World ID session-scoped proof, use `IDKit.createSession()` and store the result `session_id`. You can then use `IDKit.proveSession` with `session_id` as a parameter to log and sync existing users with their session data. ```js import { IDKit } from "@worldcoin/idkit-core"; From 7fb5aeb45d1592e5864ac51942e8d3af7b2de3f2 Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 18:54:29 -0700 Subject: [PATCH 15/21] formatting --- js/packages/core/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index 22046565..dd573bcd 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -12,7 +12,7 @@ npm install @worldcoin/idkit-core There are two ways you can request proofs with IDKit, and they depend on how you want to use the SDK. -If you want to request a World ID session-scoped proof, use `IDKit.createSession()` and store the result `session_id`. You can then use `IDKit.proveSession` with `session_id` as a parameter to log and sync existing users with their session data. +If you want to request a World ID session-scoped proof, use `IDKit.createSession()` and store the result `session_id`. You can then use `IDKit.proveSession` with `session_id` as a parameter to log and sync existing users with their session data. ```js import { IDKit } from "@worldcoin/idkit-core"; From 8a0fc4bbd099d846f6db8560eac5893b5b782c2f Mon Sep 17 00:00:00 2001 From: Kartike Chawla Date: Wed, 12 Aug 2026 19:09:20 -0700 Subject: [PATCH 16/21] fix codex comments --- js/packages/core/README.md | 90 ++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 32 deletions(-) diff --git a/js/packages/core/README.md b/js/packages/core/README.md index dd573bcd..d4825704 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -10,23 +10,32 @@ npm install @worldcoin/idkit-core ## Quickstart +### Requirements + +From the [Developer Portal](https://developer.world.org): `app_id`, `rp_id`, and an RP signing key. Keep the signing key on your backend only. + There are two ways you can request proofs with IDKit, and they depend on how you want to use the SDK. -If you want to request a World ID session-scoped proof, use `IDKit.createSession()` and store the result `session_id`. You can then use `IDKit.proveSession` with `session_id` as a parameter to log and sync existing users with their session data. +If you want to request a World ID session-scoped proof, use `IDKit.createSession()` and store the result `session_id`. You can then use `IDKit.proveSession` with `session_id` as a parameter to log and sync existing users with their session data. ```js import { IDKit } from "@worldcoin/idkit-core"; +const rp_context = await fetch("/api/rp-signature").then((r) => r.json()); + // First visit — mint a session_id and store it server-side const IDKitSessionRequest = await IDKit.createSession({ app_id: "app_xxxxx", - rp_context: { - /* from your backend */ - }, + rp_context, // pass through from your backend }).constraints(IDKit.CredentialRequest("proof_of_human")); // → IDKitRequest const result = await IDKitSessionRequest.pollUntilCompletion(); // → { success: true, result: IDKitResultSession } | { success: false, error } +if (!result.success) { + // user rejected, timeout, etc. — no result to read + console.error(result.error); + return; +} // IDKitResultSession: { // protocol_version: "4.0", // session_id: "session_", @@ -35,37 +44,44 @@ const result = await IDKitSessionRequest.pollUntilCompletion(); // environment: string, // ... // } -// save result.result.session_id in your DB +// verify on your backend first, then save result.result.session_id in your DB ``` ```js // Return visit — look up that session_id, then prove it +const rp_context = await fetch("/api/rp-signature").then((r) => r.json()); + const IDKitSessionRequest = await IDKit.proveSession(savedSessionId, { app_id: "app_xxxxx", - rp_context: { - /* from your backend */ - }, + rp_context, // pass through from your backend }).constraints(IDKit.CredentialRequest("proof_of_human")); // → IDKitRequest const result = await IDKitSessionRequest.pollUntilCompletion(); -// → { success: true, result: IDKitResultSession } | { success: false, error } +if (!result.success) { + console.error(result.error); + return; +} // same shape as createSession — result.result.session_id matches for the same user +// verify on your backend before treating the login as complete ``` -If you want to request a credential based on an action-key scope, use `IDKit.request()' and store the nullifier. +If you want to request a credential based on an action-key scope, use `IDKit.request()` and store the nullifier. ```js +const rp_context = await fetch("/api/rp-signature").then((r) => r.json()); + const request = await IDKit.request({ app_id: "app_xxxxx", - action: "claim-airdrop-2026", - rp_context: { - /* from your backend */ - }, + action: "my-action", + rp_context, // pass through from your backend allow_legacy_proofs: false, }).constraints(IDKit.CredentialRequest("proof_of_human")); // → IDKitRequest const completion = await request.pollUntilCompletion(); -// → { success: true, result: IDKitResult } | { success: false, error } +if (!completion.success) { + console.error(completion.error); + return; +} // IDKitResult (v4 uniqueness): { // protocol_version: "4.0", // action: string, @@ -75,7 +91,7 @@ const completion = await request.pollUntilCompletion(); // ... // } // send completion.result to your backend → /api/v4/verify/{rp_id} -// store the nullifier; same person + same action = reject on return +// only then store the nullifier; same person + same action = reject on return ``` ### Handling the result @@ -126,17 +142,11 @@ browser global; generate RP signatures on your backend with