From 8c21238dde0738387956d958f65ba4cc1a14618e Mon Sep 17 00:00:00 2001 From: Takis Kakalis <80459599+Takaros999@users.noreply.github.com> Date: Wed, 21 Oct 2026 00:16:14 +0000 Subject: [PATCH 1/4] docs(world-id): create sessions with uniqueness proofs --- world-id/idkit/session-proofs.mdx | 54 +++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/world-id/idkit/session-proofs.mdx b/world-id/idkit/session-proofs.mdx index 8e07609..7f6be74 100644 --- a/world-id/idkit/session-proofs.mdx +++ b/world-id/idkit/session-proofs.mdx @@ -13,6 +13,10 @@ A uniqueness request allows each user to complete a particular action once. A session lets the user prove continuity across multiple checks: create it once, then prove the saved session on subsequent checks. +Session IDs alone do not prevent the same person from enrolling more than once. +To enforce uniqueness at enrollment and verify returning users afterward, +[create a session with a uniqueness proof](#create-a-session-with-a-uniqueness-proof). + | Value | Purpose | Backend responsibility | | --- | --- | --- | | `session_id` | Identifies the session across checks. | Associate the verified value with your application account and require it on later checks. | @@ -28,8 +32,10 @@ and use the same [backend verification endpoint](/world-id/idkit/integrate#step- as other IDKit flows. This guide covers the session-specific changes. Generate fresh [RP signatures](/world-id/idkit/signatures) for session creation and -each subsequent check. Call `signRequest({ signingKeyHex })` without an `action`; -session requests do not take an action or support legacy proofs. +each subsequent check. For session-only requests, call +`signRequest({ signingKeyHex })` without an `action`. A uniqueness request that +also creates a session includes an action, as shown below. Neither flow supports +legacy proofs. In IDKit 4.4.0, session builders require `.constraints(...)`; `.preset(...)` @@ -67,6 +73,50 @@ Associate it with the account completing enrollment. Treat linking or replacing an account's session as an account-security operation; do not silently replace the saved value whenever the client submits a new session. +## Create a session with a uniqueness proof + +During enrollment, use `IDKit.request` with an `action` and +`session_id: "create"`. This produces one uniqueness proof that also binds a new +session, so the user can enroll and establish continuity in the same request. + +Use the same enrollment action for all users, such as `"signup"`. On your backend, +generate the RP signature with `signRequest({ signingKeyHex, action: "signup" })` +and use its values in `rp_context`. The signed action must match the request below. + +```typescript +import { IDKit, CredentialRequest } from "@worldcoin/idkit-core"; + +const request = await IDKit.request({ + app_id, + action: "signup", + session_id: "create", + rp_context, + allow_legacy_proofs: false, + environment: "production", +}).constraints(CredentialRequest("selfie")); + +// Display request.connectorURI as a link or QR code, then wait for the user. +const completion = await request.pollUntilCompletion({ timeout: 120_000 }); +if (!completion.success) throw new Error(completion.error); + +// Send completion.result unchanged to your backend for verification. +``` + +The World ID 4.0 result contains both `action` and `session_id`, with a uniqueness +`nullifier` in each credential response. For this enrollment request, use that +nullifier to enforce uniqueness: + +1. Verify the complete result, including `action` and `session_id`, through your + backend verification endpoint. Require the expected enrollment action. +2. Reject a nullifier already used for enrollment under this app and action. +3. Save the verified nullifier and session ID against the account only after both + checks succeed. Enforce nullifier uniqueness in your database to prevent + concurrent requests from enrolling the same person twice. + +For later checks, [prove the saved session](#verify-a-returning-user) with a fresh +RP signature without an action. Keep the original enrollment nullifier; subsequent +session proofs return `session_nullifier` values for replay protection. + ## Verify a returning user Load the saved session ID from your backend for the account being verified, and From df04e3d3aca6e276c66519eabfcb5756c7f0722d Mon Sep 17 00:00:00 2001 From: Takis Kakalis <80459599+Takaros999@users.noreply.github.com> Date: Wed, 21 Oct 2026 00:23:38 +0000 Subject: [PATCH 2/4] docs: clarify enrollment uniqueness and nullifier storage --- world-id/idkit/session-proofs.mdx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/world-id/idkit/session-proofs.mdx b/world-id/idkit/session-proofs.mdx index 7f6be74..d1db0a4 100644 --- a/world-id/idkit/session-proofs.mdx +++ b/world-id/idkit/session-proofs.mdx @@ -110,8 +110,11 @@ nullifier to enforce uniqueness: backend verification endpoint. Require the expected enrollment action. 2. Reject a nullifier already used for enrollment under this app and action. 3. Save the verified nullifier and session ID against the account only after both - checks succeed. Enforce nullifier uniqueness in your database to prevent - concurrent requests from enrolling the same person twice. + checks succeed. [Enforce nullifier uniqueness in your database](/world-id/idkit/integrate#step-6-store-the-nullifier) + to prevent concurrent requests from enrolling the same World ID twice. + +Uniqueness assurance depends on the selected credential. +[Selfie Check](/world-id/credentials/11) remains a medium-assurance credential. For later checks, [prove the saved session](#verify-a-returning-user) with a fresh RP signature without an action. Keep the original enrollment nullifier; subsequent From e53dcaa0b22be951bad4531299bdf9ee29515ae9 Mon Sep 17 00:00:00 2001 From: Takis Kakalis <80459599+Takaros999@users.noreply.github.com> Date: Wed, 21 Oct 2026 20:39:51 +0000 Subject: [PATCH 3/4] docs: use explicit session creation flag --- world-id/idkit/session-proofs.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/world-id/idkit/session-proofs.mdx b/world-id/idkit/session-proofs.mdx index d1db0a4..6a90c00 100644 --- a/world-id/idkit/session-proofs.mdx +++ b/world-id/idkit/session-proofs.mdx @@ -76,8 +76,9 @@ the saved value whenever the client submits a new session. ## Create a session with a uniqueness proof During enrollment, use `IDKit.request` with an `action` and -`session_id: "create"`. This produces one uniqueness proof that also binds a new +`create_session: true`. This produces one uniqueness proof that also binds a new session, so the user can enroll and establish continuity in the same request. +The older `session_id: "create"` option remains supported but is deprecated. Use the same enrollment action for all users, such as `"signup"`. On your backend, generate the RP signature with `signRequest({ signingKeyHex, action: "signup" })` @@ -89,7 +90,7 @@ import { IDKit, CredentialRequest } from "@worldcoin/idkit-core"; const request = await IDKit.request({ app_id, action: "signup", - session_id: "create", + create_session: true, rp_context, allow_legacy_proofs: false, environment: "production", From 51662529f4d343708d5ac6648c65fc06cb24d2dd Mon Sep 17 00:00:00 2001 From: Takis Kakalis <80459599+Takaros999@users.noreply.github.com> Date: Wed, 21 Oct 2026 20:50:24 +0000 Subject: [PATCH 4/4] docs: keep published session creation API --- world-id/idkit/session-proofs.mdx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/world-id/idkit/session-proofs.mdx b/world-id/idkit/session-proofs.mdx index 6a90c00..d1db0a4 100644 --- a/world-id/idkit/session-proofs.mdx +++ b/world-id/idkit/session-proofs.mdx @@ -76,9 +76,8 @@ the saved value whenever the client submits a new session. ## Create a session with a uniqueness proof During enrollment, use `IDKit.request` with an `action` and -`create_session: true`. This produces one uniqueness proof that also binds a new +`session_id: "create"`. This produces one uniqueness proof that also binds a new session, so the user can enroll and establish continuity in the same request. -The older `session_id: "create"` option remains supported but is deprecated. Use the same enrollment action for all users, such as `"signup"`. On your backend, generate the RP signature with `signRequest({ signingKeyHex, action: "signup" })` @@ -90,7 +89,7 @@ import { IDKit, CredentialRequest } from "@worldcoin/idkit-core"; const request = await IDKit.request({ app_id, action: "signup", - create_session: true, + session_id: "create", rp_context, allow_legacy_proofs: false, environment: "production",