Anonymous Actions
Verifying Proofs via API
This section describes how to verify proofs via the Developer Portal API.
You must first pass the proof to your backend when verifying proofs via the API. The user can manipulate information in the frontend, so you the proof must be verified in a trusted environment.
Send the Proof to Your Backend
The proof returned from IDKit includes the merkle_root
, nullifier_hash
, proof
, and credential_type
fields:
ISuccessResult
{
"credential_type": "orb",
"merkle_root": "0x1f38b57f3bdf96f05ea62fa68814871bf0ca8ce4dbe073d8497d5a6b0a53e5e0",
"nullifier_hash": "0x0339861e70a9bdb6b01a88c7534a3332db915d3d06511b79a5724221a6958fbe",
"proof": "0x063942fd7ea1616f17787d2e3374c1826ebcd2d41d2394..."
}
Send these fields to your backend along with the action name. It's recommended to do this in the handleVerify
callback function. Any errors thrown in this function will be displayed to the user in IDKit.
Here's an example of how to send the proof to your backend. Assume a backend endpoint /api/verify
:
pages/index.tsx
const handleVerify = async (result: ISuccessResult) => { // called by IDKit
// build the request body
const reqBody = {
merkle_root: result.merkle_root,
nullifier_hash: result.nullifier_hash,
proof: result.proof,
credential_type: result.credential_type,
action: process.env.NEXT_PUBLIC_WLD_ACTION_NAME,
signal: "",
};
const res: Response = await fetch("/api/verify", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(reqBody),
})
const data: VerifyReply = await res.json()
if (res.status == 200) {
console.log("Verification successful!")
} else {
throw new Error(`Error code ${res.status} (${data.code}): ${data.detail ?? "Unknown error."}`); // Throw an error if verification fails
}
};
Verify the Proof in Your Backend
Here our backend receives the proof sent from the frontend, and sends it to the Developer Portal API for verification.
The Developer Portal API will return a 200
response if the proof is valid, and a 400
response with extra error detail if the proof is invalid.
We then pass the success or error messages back to our frontend after performing our own backend actions.
pages/api/verify.ts
export type VerifyReply = {
code: string;
detail?: string;
};
export default function handler(req: NextApiRequest, res: NextApiResponse<VerifyReply>) {
fetch(`https://developer.worldcoin.org/api/v1/verify/${process.env.NEXT_PUBLIC_WLD_APP_ID}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
// note that we pass the body of the request directly to the World ID /verify endpoint
body: JSON.stringify(req.body),
}).then((verifyRes) => {
verifyRes.json().then((wldResponse) => {
if (verifyRes.status == 200) {
// this is where you should perform backend actions based on the verified credential
// i.e. setting a user as "verified" in a database
res.status(verifyRes.status).send({ code: "success" });
} else {
// return the error code and detail from the World ID /verify endpoint to our frontend
res.status(verifyRes.status).send({
code: wldResponse.code,
detail: wldResponse.detail
});
}
});
});
}
Post-Verification
If handleVerify
is does not throw an error, the user will see a success state and the onSuccess
callback will be called when the modal is closed. The onSuccess
callback should redirect a user to a success page, or perform any other actions you want to take after a user has been verified.
pages/index.tsx
const onSuccess = (result: ISuccessResult) => {
// This is where you should perform frontend actions once a user has been verified
window.alert(`Successfully verified with World ID!
Your nullifier hash is: ` + result.nullifier_hash);
};