Browser v4 uniqueness flow: constraints(proof_of_human) emits mixed-mode bridge payload and falls back to legacy / verification_rejected
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 9
- Forks
- 6
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 12
Description
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.- 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_969d38c8ba9adf22a4ac3b2d4400575arp_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
signalentirely in this repro to keep the request as simple as possible. - We also omitted
genesis_issued_at_minto 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: falseCredentialRequest("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
signalwhen no signal is intended
- top-level
- What conditions cause
verification_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_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.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating the browser request builder and wasm bridge serialization in @worldcoin/idkit-core@4.1.0, then reproduce both payloads from the issue and compare their bridge responses. Check the captured request IDs and the SDK-generated verification_level field first. Done means the expected pure v4 request shape and the cause of verification_rejected are established, with a regression test or documented behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript, wasm
- Domain
- api, developer-experience
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 45/100