Summary
We are integrating World ID 4.0 for an on-chain uniqueness-gated flow and hit two related problems in the browser path:
@worldcoin/idkit-core@4.1.0 with IDKit.request(...).constraints(CredentialRequest('proof_of_human')) emitted a mixed-mode bridge request that included a top-level verification_level: "device", and the World App completed with a legacy protocol_version: "3.0" result.
- After bypassing the SDK request builder and sending a pure v4 bridge payload ourselves, the request no longer returned a legacy proof, but the World App/bridge completed with
verification_rejected.
At this point we are no longer trying to prove that our app works; we have a minimal repro that seems to isolate the request semantics.
Environment
@worldcoin/idkit-core: 4.1.0
- Browser integration, not React
- Production environment
- RP is registered for World ID 4.0 in the Developer Portal
app_id: app_969d38c8ba9adf22a4ac3b2d4400575a
rp_id: rp_6765160973bf7042
Repro 1: official SDK browser flow
Code shape:
const request = await IDKit.request({
app_id,
action: "create-auction",
rp_context,
allow_legacy_proofs: false,
environment: "production",
}).constraints(
CredentialRequest("proof_of_human")
)
const result = await request.pollUntilCompletion()
What we observed
Even though allow_legacy_proofs was false, the raw result was:
{
"success": true,
"result": {
"action": "create-auction",
"environment": "production",
"nonce": "0x...",
"protocol_version": "3.0",
"responses": [
{
"identifier": "orb",
"merkle_root": "0x...",
"nullifier": "0x...",
"proof": "0x...",
"signal_hash": "0x00c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4"
}
]
}
}
What we found by instrumenting the SDK request
We captured the browser POST to https://bridge.worldcoin.org/request, decrypted the payload, and found that the SDK-generated request was not pure v4. It included a top-level legacy-looking field:
{
"allow_legacy_proofs": false,
"proof_request": {
"proof_requests": [
{
"identifier": "proof_of_human",
"issuer_schema_id": 1,
"genesis_issued_at_min": 1775260800
}
],
"rp_id": "rp_6765160973bf7042",
"version": 1
},
"signal": "0x00c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4",
"verification_level": "device"
}
The presence of verification_level: "device" is what led us to suspect the browser request builder was emitting a mixed-mode payload.
Repro 2: pure v4 bridge request (no SDK request builder)
We then bypassed IDKit.request(...).constraints(...) and constructed the bridge request ourselves.
The payload we sent was:
{
"action": "create-auction",
"allow_legacy_proofs": false,
"app_id": "app_969d38c8ba9adf22a4ac3b2d4400575a",
"environment": "production",
"proof_request": {
"action": "0x00c13e38e42d2818b1b66349184c1ad52cce0d9f2d6e61b58264e3c47f592270",
"created_at": 1775338401,
"expires_at": 1775338701,
"id": "82ef1792-c31c-47cb-a4d8-3c0fd97ab30b",
"nonce": "0x0045e7472500630a9751a115500e9bd0b5fb5201e79bd19cd363c018c910bb10",
"oprf_key_id": "0x6765160973bf7042",
"proof_requests": [
{
"identifier": "proof_of_human",
"issuer_schema_id": 1,
"genesis_issued_at_min": null,
"expires_at_min": null
}
],
"rp_id": "rp_6765160973bf7042",
"session_id": null,
"signature": "<redacted>",
"version": 1
}
}
Notes:
- We omitted
signal entirely in this repro to keep the request as simple as possible.
- We also omitted
genesis_issued_at_min to avoid unnecessarily excluding older credentials.
- We did not include
verification_level.
Bridge request ID for this clean repro:
2bf813bf-43ec-4985-b6a6-7ab7efc25700
Result
This no longer returned a legacy 3.0 proof. Instead it completed with:
{
"success": false,
"error": "verification_rejected",
"rawResult": {
"error_code": "verification_rejected"
}
}
So after removing the mixed-mode request shape, the behavior changed from “legacy proof returned” to “request rejected”.
Questions
- Is
verification_level: "device" expected in the browser bridge payload for a v4 uniqueness request built from:
allow_legacy_proofs: false
CredentialRequest("proof_of_human")
?
- If not, is this a bug in the browser request builder / wasm bridge serialization for
@worldcoin/idkit-core@4.1.0?
- For a pure v4 browser request, is the payload shape above correct, especially:
- top-level
action
proof_request.action = hashSignal(action)
proof_requests: [{ identifier: "proof_of_human", issuer_schema_id: 1 }]
- omission of
signal when no signal is intended
- What conditions cause
verification_rejected at this stage for a pure v4 uniqueness request in production?
Why we are filing this here
The first issue appears squarely in IDKit itself: the browser request builder emitted a bridge payload that mixed v4 proof_request with a legacy-looking top-level verification_level, and that correlated with a legacy 3.0 result.
We can share more implementation details if useful, but the payloads and request IDs above should be enough to inspect bridge-side behavior.
Summary
We are integrating World ID 4.0 for an on-chain uniqueness-gated flow and hit two related problems in the browser path:
@worldcoin/idkit-core@4.1.0withIDKit.request(...).constraints(CredentialRequest('proof_of_human'))emitted a mixed-mode bridge request that included a top-levelverification_level: "device", and the World App completed with a legacyprotocol_version: "3.0"result.verification_rejected.At this point we are no longer trying to prove that our app works; we have a minimal repro that seems to isolate the request semantics.
Environment
@worldcoin/idkit-core:4.1.0app_id:app_969d38c8ba9adf22a4ac3b2d4400575arp_id:rp_6765160973bf7042Repro 1: official SDK browser flow
Code shape:
What we observed
Even though
allow_legacy_proofswasfalse, the raw result was:{ "success": true, "result": { "action": "create-auction", "environment": "production", "nonce": "0x...", "protocol_version": "3.0", "responses": [ { "identifier": "orb", "merkle_root": "0x...", "nullifier": "0x...", "proof": "0x...", "signal_hash": "0x00c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4" } ] } }What we found by instrumenting the SDK request
We captured the browser POST to
https://bridge.worldcoin.org/request, decrypted the payload, and found that the SDK-generated request was not pure v4. It included a top-level legacy-looking field:{ "allow_legacy_proofs": false, "proof_request": { "proof_requests": [ { "identifier": "proof_of_human", "issuer_schema_id": 1, "genesis_issued_at_min": 1775260800 } ], "rp_id": "rp_6765160973bf7042", "version": 1 }, "signal": "0x00c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4", "verification_level": "device" }The presence of
verification_level: "device"is what led us to suspect the browser request builder was emitting a mixed-mode payload.Repro 2: pure v4 bridge request (no SDK request builder)
We then bypassed
IDKit.request(...).constraints(...)and constructed the bridge request ourselves.The payload we sent was:
{ "action": "create-auction", "allow_legacy_proofs": false, "app_id": "app_969d38c8ba9adf22a4ac3b2d4400575a", "environment": "production", "proof_request": { "action": "0x00c13e38e42d2818b1b66349184c1ad52cce0d9f2d6e61b58264e3c47f592270", "created_at": 1775338401, "expires_at": 1775338701, "id": "82ef1792-c31c-47cb-a4d8-3c0fd97ab30b", "nonce": "0x0045e7472500630a9751a115500e9bd0b5fb5201e79bd19cd363c018c910bb10", "oprf_key_id": "0x6765160973bf7042", "proof_requests": [ { "identifier": "proof_of_human", "issuer_schema_id": 1, "genesis_issued_at_min": null, "expires_at_min": null } ], "rp_id": "rp_6765160973bf7042", "session_id": null, "signature": "<redacted>", "version": 1 } }Notes:
signalentirely in this repro to keep the request as simple as possible.genesis_issued_at_minto avoid unnecessarily excluding older credentials.verification_level.Bridge request ID for this clean repro:
2bf813bf-43ec-4985-b6a6-7ab7efc25700Result
This no longer returned a legacy
3.0proof. Instead it completed with:{ "success": false, "error": "verification_rejected", "rawResult": { "error_code": "verification_rejected" } }So after removing the mixed-mode request shape, the behavior changed from “legacy proof returned” to “request rejected”.
Questions
verification_level: "device"expected in the browser bridge payload for a v4 uniqueness request built from:allow_legacy_proofs: falseCredentialRequest("proof_of_human")?
@worldcoin/idkit-core@4.1.0?actionproof_request.action = hashSignal(action)proof_requests: [{ identifier: "proof_of_human", issuer_schema_id: 1 }]signalwhen no signal is intendedverification_rejectedat this stage for a pure v4 uniqueness request in production?Why we are filing this here
The first issue appears squarely in IDKit itself: the browser request builder emitted a bridge payload that mixed v4
proof_requestwith a legacy-looking top-levelverification_level, and that correlated with a legacy3.0result.We can share more implementation details if useful, but the payloads and request IDs above should be enough to inspect bridge-side behavior.