diff --git a/world-id/idkit/session-proofs.mdx b/world-id/idkit/session-proofs.mdx index 8e07609..d1db0a4 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,53 @@ 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](/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 +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