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
5 changes: 4 additions & 1 deletion docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@
},
{
"group": "Migration",
"pages": ["world-id/4-0-migration"]
"pages": [
"world-id/4-0-migration",
"world-id/from-idkit-standalone"
]
},
{
"group": "Technical Reference",
Expand Down
188 changes: 188 additions & 0 deletions world-id/from-idkit-standalone.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
---
title: "IDKit Standalone"
description: "Migrate from @worldcoin/idkit-standalone to @worldcoin/idkit-core."
"og:image": "https://raw.githubusercontent.com/worldcoin/developer-docs/main/images/docs/docs-meta.png"
"twitter:image": "https://raw.githubusercontent.com/worldcoin/developer-docs/main/images/docs/docs-meta.png"
---

{/* cspell:ignore idkit standalone rp_context app_id rp_id orblegacy signal_hash nullifier nullifiers verifyCloudProof pollUntilCompletion connectorURI */}

This guide helps you migrate from `@worldcoin/idkit-standalone` to `@worldcoin/idkit-core`. The `idkit-standalone` package has been discontinued. If you used it
for a vanilla JavaScript or custom QR flow, migrate to `@worldcoin/idkit-core`.
¡
## Migration Checklist

1. Enable World ID 4.0 in the [Developer Portal](https://developer.world.org) and keep your `app_id`, `rp_id`, and server-only `signing_key`.
2. Install `@worldcoin/idkit-core`.
3. Add a backend endpoint that generates an RP signature. See [RP Signatures](/world-id/idkit/signatures).
4. Pick a legacy preset that matches your previous `verification_level` configuration.
5. Replace `verifyCloudProof(...)` with a backend POST to `https://developer.world.org/api/v4/verify/{rp_id}`.
6. Store the verified `nullifier` for replay protection.

For the broader protocol migration, including proof types and timelines, see
[World ID 4.0](/world-id/4-0-migration).

## Install

<CodeGroup>
```bash npm
npm i @worldcoin/idkit-core
```

```bash pnpm
pnpm add @worldcoin/idkit-core
```

```bash yarn
yarn add @worldcoin/idkit-core
```
</CodeGroup>

## Request a Proof

In standalone, the package mounted UI through browser globals:

```ts title="Before"
import "@worldcoin/idkit-standalone";

IDKit.init({
app_id: "app_xxxxx",
action: "my-action",
signal: "user-123",
verification_level: "orb",
});

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.

```ts title="After"
import { IDKit, orbLegacy } from "@worldcoin/idkit-core";

const action = "my-action";
const signal = "user-123";

const rpContext = await fetch("/api/rp-signature", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ action }),
}).then((r) => r.json());

const request = await IDKit.request({
app_id: "app_xxxxx",
action,
rp_context: {
rp_id: "rp_xxxxx",
nonce: rpContext.nonce,
created_at: rpContext.created_at,
expires_at: rpContext.expires_at,
signature: rpContext.sig,
},
allow_legacy_proofs: true,
environment: "production",
}).preset(orbLegacy({ signal }));

renderQrCode(request.connectorURI);

const completion = await request.pollUntilCompletion({
pollInterval: 2_000,
timeout: 120_000,
});

if (!completion.success) {
throw new Error(`World ID verification failed: ${completion.error}`);
}

await fetch("/api/verify-proof", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ idkitResponse: completion.result }),
});
```

## Credential Mapping

Standalone used `verification_level` to choose what the user should prove. In
`idkit-core`, use a legacy preset instead. These presets are drop-in
replacements for the old verification levels.

<Note type="info">
The legacy presets will return the maximum credential a user has. For example, if a user has an Orb credential, but you request `documentLegacy`, they will verify with their Orb credential.
</Note>

| Standalone | `idkit-core` preset |
| --- | --- |
| `verification_level: "orb"` | `orbLegacy({ signal })` |
| `verification_level: "secure_document"` | `secureDocumentLegacy({ signal })` |
| `verification_level: "document"` | `documentLegacy({ signal })` |
| `verification_level: "device"` | `deviceLegacy({ signal })` |

```ts
import {
IDKit,
deviceLegacy,
documentLegacy,
orbLegacy,
secureDocumentLegacy,
} from "@worldcoin/idkit-core";

const request = await IDKit.request(config).preset(
orbLegacy({ signal: "user-123" }),
);
```


## RP Signatures

IDKit 4.x requests require `rp_context`, signed by your backend with the
Developer Portal `signing_key`. Do not generate signatures in client code.

For implementation details, use the [RP Signatures](/world-id/idkit/signatures)
reference. It includes the JavaScript helper, the signing algorithm, and test
vectors for non-JavaScript backends.

## Verify the Proof

Standalone integrations usually verified with `verifyCloudProof(...)`:

```ts title="Before"
import { verifyCloudProof } from "@worldcoin/idkit";

const response = await verifyCloudProof(proof, app_id, action, signal);
```

In IDKit 4.x, send the IDKit result to your backend and forward it directly to
the [v4 verify endpoint](/api-reference/developer-portal/verify).

```ts title="After"
import type { IDKitResult } from "@worldcoin/idkit-core";

export async function POST(request: Request): Promise<Response> {
const { idkitResponse } = (await request.json()) as {
idkitResponse: IDKitResult;
};

const response = await fetch(
`https://developer.world.org/api/v4/verify/${process.env.WORLD_ID_RP_ID}`,
{
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(idkitResponse),
},
);

return new Response(await response.text(), {
status: response.status,
headers: { "content-type": "application/json" },
});
}
```

## Store the Nullifier

After `/api/v4/verify/{rp_id}` succeeds, store the verified `nullifier` for the
action and reject duplicates. During migration, keep checking any old
`nullifier_hash` records if the same user could have verified before the
upgrade.
Loading