Skip to content

Commit

Permalink
feat: final v1 updates (#252)
Browse files Browse the repository at this point in the history
* fix: verification_level, World ID Device, OIDC claim

* feat: idkit v1.1, update incognito actions section of try it page

* feat: verification levels page

merged "World ID Device" and "Proof of Personhood" pages to create this

* fix: remove theme param and add to migration guide

* feat: user-agent header requirement

* fix: try page theme

* fix: closing tag

* feat: verify with world id page

* feat: errors reorg

* fix: feedback
  • Loading branch information
0xPenryn authored Dec 13, 2023
1 parent 3bf20ed commit 656b4ca
Show file tree
Hide file tree
Showing 18 changed files with 348 additions and 979 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@sindresorhus/slugify": "^2.1.1",
"@tailwindcss/typography": "^0.5.8",
"@vercel/og": "^0.5.7",
"@worldcoin/idkit": "^0.5.1",
"@worldcoin/idkit": "^1.1.0",
"acorn": "^8.8.1",
"autoprefixer": "^10.4.7",
"clsx": "^1.2.1",
Expand Down
852 changes: 149 additions & 703 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/components/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,13 @@ export const navigation = [
{
title: 'World ID',
links: [
{ title: 'Verify with World ID', href: '/id/verify-with-world-id' },
{ title: 'Sign in with World ID', href: '/id/sign-in' },
{ title: 'Incognito Actions', href: '/id/incognito-actions' },
{ title: 'Intro to IDKit', href: '/id/idkit' },
{ title: 'Cloud Verification', href: '/id/cloud' },
{ title: 'On-Chain Verification', href: '/id/on-chain' },
{ title: 'World ID Lite', href: '/id/world-id-lite' },
{ title: 'Verification Levels', href: '/id/verification-levels' },
],
},
{
Expand All @@ -199,7 +200,6 @@ export const navigation = [
{
title: 'Further Reading',
links: [
{ title: 'Proof of Personhood', href: '/proof-of-personhood' },
{ title: 'OIDC Explainer', href: '/further-reading/oidc' },
{ title: 'Protocol Internals', href: '/further-reading/protocol-internals' },
{ title: 'Zero-Knowledge Proofs', href: '/further-reading/zero-knowledge-proofs' },
Expand Down
8 changes: 5 additions & 3 deletions src/pages/further-reading/protocol-internals.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The Wallet Bridge acts as the intermediary between IDKit and the user's World ID
![Wallet Bridge Diagram](/images/docs/world-id-bridge.png)

<Note>
All requests to the Wallet Bridge must include a `Content-Type: application/json` header and a valid JSON body.
All requests to the Wallet Bridge must include a `Content-Type: application/json` header, a `User-Agent` header, and a valid JSON body.
</Note>
1. IDKit initiates the proof request session on the Wallet Bridge.
- An app configures and opens IDKit with the required parameters `app_id` and `action`, and the optional parameters `signal`, `credential_types`, and `action_description`.
Expand Down Expand Up @@ -147,9 +147,11 @@ Within the ID token returned by the World ID provider, a minimal number of [OIDC
- `exp`: The timestamp of the token's expiration
- `alg`: The algorithm used to sign the ID token, only RS256 is supported
- `scope`: The scopes requested by the application. Must always contain `openid`. The `profile` and `email` scopes are also supported for compatibility, but use should be avoided.
- `https://worldcoin.org/beta`: Describes claims specific to World ID. **Subject to change**
- `https://worldcoin.org/beta`: Describes claims specific to World ID. **Deprecated and replaced by `https://id.worldcoin.org/v1`**.
- `likely_human`: "strong" or "weak", corresponding to whether the user has strong sybil protection or likelihood of being human. Biometrically verified users have a `strong` value.
- `credential_type`: `orb` or `device`, represents the credential the user to authenticate. In general, for Sign in with World ID, the highest credential available to the user will be used.
- `credential_type`: `orb` or `device`, represents the credential the user used to authenticate. In general, for Sign in with World ID, the highest credential available to the user will be used.
- `https://worldcoin.org/v1`: Describes claims specific to World ID.
- `verification_level`: `orb` or `device`, represents the verification level of the user. In general, for Sign in with World ID, the highest verification level available to the user will be used.

## Signup Sequencer

Expand Down
36 changes: 3 additions & 33 deletions src/pages/id/cloud.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ 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.
</Note>

Our backend should receive the `proof`, `merkle_root`, `nullifier_hash`, and `credential_type` from IDKit, as well as the same `action` and `signal` as were input into IDKit, and send it to the **Developer Portal API** for verification.
Our backend should receive the `proof`, `merkle_root`, `nullifier_hash`, and `verification_level` from IDKit, as well as the same `action` and `signal` as were input into IDKit, and send 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.

Expand All @@ -21,7 +21,7 @@ export default function handler(req: NextApiRequest, res: NextApiResponse<Verify
merkle_root: req.body.merkle_root,
nullifier_hash: req.body.nullifier_hash,
proof: req.body.proof,
credential_type: req.body.credential_type,
verification_level: req.body.verification_level,
action: req.body.action, // or get this from environment variables,
signal: req.body.signal ?? "", // if we don't have a signal, use the empty string
};
Expand Down Expand Up @@ -63,34 +63,4 @@ const onSuccess = (result: ISuccessResult) => {

<Note>
For more information on configuration, see the [IDKit](/reference/idkit) and [Cloud API](/api/reference) reference pages.
</Note>

{/* Verify your action by sending the zero knowledge proof to the **Developer Portal API**. Please check the [API reference](/api/reference#verify) for details on anticipated error responses.
<CodeGroup title="API Verification" tag="POST" label="/api/v1/verify/app_GBkZ1KlVUdFTjeMXKlVUdFT">
```json {{ title: "Request" }}
{
"action": "vote_1",
"signal": "user_value",
"credential_type": "orb",
"merkle_root": "0x1f38b57f3bdf96f05ea62fa68814871bf0ca8ce4dbe073d8497d5a6b0a53e5e0",
"nullifier_hash": "0x0339861e70a9bdb6b01a88c7534a3332db915d3d06511b79a5724221a6958fbe",
"proof": "0x063942fd7ea1616f17787d2e3374c1826ebcd2d41d2394d915098c73482fa59516145cee11d59158b4012a463f487725cb3331bf90a0472e17385832eeaec7a713164055fc43cc0f873d76752de0e35cc653346ec42232649d40f5b8ded28f202793c4e8d096493dc34b02ce4252785df207c2b76673924502ab56b7e844baf621025148173fc74682213753493e8c90e5c224fc43786fcd09b624115bee824618e57bd28caa301f6b21606e7dce789090de053e641bce2ce0999b64cdfdfb0a0734413914c21e4e858bf38085310d47cd4cc6570ed634faa2246728ad64c49f1f720a39530d82e1fae1532bd7ad389978b6f337fcd6fa6381869637596e63a1"
}
``` */}

{/* cSpell:enable */}

{/* ```json {{ title: 'Response' }}
{
"success": true,
"nullifier_hash": "0x2bf8406809dcefb1486dadc96c0a897db9bab002053054cf64272db512c6fbd8",
"action": "vote_1",
"created_at": "2023-01-01T12:12:12.000Z"
}
```
</CodeGroup>
7. The user is a unique human! Execute your action on your backend (e.g. claim the user promotion). */}
</Note>
9 changes: 5 additions & 4 deletions src/pages/id/idkit.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ Import and render IDKit. You'll want to do this on the screen where the user exe

```tsx
import { IDKitWidget } from '@worldcoin/idkit'

<IDKitWidget
app_id="app_GBkZ1KlVUdFTjeMXKlVUdFT" // obtained from the Developer Portal
action="vote_1" // this is your action name from the Developer Portal
onSuccess={onSuccess} // callback when the modal is closed
handleVerify={handleVerify} // optional callback when the proof is received
credential_types={['orb', 'device']} // optional, defaults to ['orb']
verification_level={VerificationLevel.Device}
>
{({ open }) => <button onClick={open}>Verify with World ID</button>}
</IDKitWidget>
Expand Down Expand Up @@ -94,7 +95,7 @@ Upon successful completion of the World ID flow, you will receive a response obj
"merkle_root": "0x1f38b57f3bdf96f05ea62fa68814871bf0ca8ce4dbe073d8497d5a6b0a53e5e0",
"nullifier_hash": "0x0339861e70a9bdb6b01a88c7534a3332db915d3d06511b79a5724221a6958fbe",
"proof": "0x063942fd7ea1616f17787d2e3374c1826ebcd2d41d2394...",
"credential_type": "orb"
"verification_level": "orb"
}
```

Expand All @@ -109,8 +110,8 @@ Upon successful completion of the World ID flow, you will receive a response obj
<Property name="proof" type="string">
The Zero-knowledge proof of the verification. ABI encoded.
</Property>
<Property name="credential_type" type='"orb" | "device"'>
Either `orb` or `device`. Will always return the strongest credential with which a user has been verified.
<Property name="verification_level" type='"orb" | "device"'>
Either `orb` or `device`. Returns the verification_level used to generate the proof.
</Property>
</Properties>

Expand Down
8 changes: 4 additions & 4 deletions src/pages/id/on-chain.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ This setup is recommended for most users, as it is the most gas-efficient. For m

## IDKit Configuration

When verifying proofs on-chain, there are a few changes you have to make to your IDKit configuration. You must ensure that the app created in the Developer Portal is configured as an on-chain app, and you should only accept Orb credentials in IDKit, as World ID Lite is not currently supported on-chain.
When verifying proofs on-chain, there are a few changes you have to make to your IDKit configuration. You must ensure that the app created in the Developer Portal is configured as an on-chain app, and you should only accept Orb credentials in IDKit, as World ID Device is not currently supported on-chain.

```tsx
import { IDKitWidget } from '@worldcoin/idkit'
Expand All @@ -30,7 +30,7 @@ const { address } = useAddress() // get the user's wallet address
signal={address} // proof will only verify if the signal is unchanged, this prevents tampering
onSuccess={onSuccess} // use onSuccess to call your smart contract
// no use for handleVerify, so it is removed
// use default credential_types (orb-only), as device credentials are not supported on-chain
// use default verification_level (orb-only), as device credentials are not supported on-chain
>
{({ open }) => <button onClick={open}>Verify with World ID</button>}
</IDKitWidget>
Expand Down Expand Up @@ -73,7 +73,7 @@ contract HelloWorld {
The `externalNullifier` is the unique identifier of the action performed in Semaphore, and its keccak256 hash (named `externalNullifierHash`) is what is passed to the World ID Router contract. It is a combination of the app ID and the action.
You should typically set it in the constructor to save gas (as is done in this example), as it will not change if all users are performing the same action.

We additionally set the `groupId` to `1`, which limits this example to Orb-verified users only. World ID Lite is currently not supported on-chain.
We additionally set the `groupId` to `1`, which limits this example to Orb-verified users only. World ID Device is currently not supported on-chain.

```solidity
/// @dev This allows us to use our hashToField function on bytes
Expand Down Expand Up @@ -123,7 +123,7 @@ The `verifyProof` method reverts if the proof is invalid, meaning you can just c
The `verifyProof` method takes the arguments below.

- `root` - The World ID root to verify against. This is obtained from the IDKit widget, and should be passed as-is.
- `groupId` - This must be `1` for Orb-verified users. World ID Lite is currently not supported on-chain.
- `groupId` - This must be `1` for Orb-verified users. World ID Device is currently not supported on-chain.
- `signalHash` - The keccak256 hash of the signal to verify.
- `nullifierHash` - Anonymous user ID for this action. This is obtained from the IDKit widget, and should just be passed as-is.
- `externalNullifierHash` - The externalNullifierHash, which identifies which app and action the user is verifying for.
Expand Down
9 changes: 7 additions & 2 deletions src/pages/id/sign-in.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,20 @@ World ID can be used as an authentication mechanism. Some helpful resources for

## Mapping User Info

<Note>The `https://id.worldcoin.org/beta` claim has been deprecated and replaced by `https://id.worldcoin.org/v1`.</Note>

The `/userinfo` endpoint or `id_token` JWT returns a JSON object with the following fields:

```json {{ title: "Response" }}
{
"sub": "0x2ae86d6d747702b3b2c81811cd2b39875e8fa6b780ee4a207bdc203a7860b535",
"https://id.worldcoin.org/beta": {
"https://id.worldcoin.org/beta": { // deprecated, will be removed in the future
"likely_human": "strong",
"credential_type": "orb"
},
"https://id.worldcoin.org/v1": {
"verification_level": "orb", // "orb" or "device"
},
// if `email` scope is included:
"email": "0x2ae86d6d747702b3b2c81811cd2b39875e8fa6b780ee4a207bdc203a7860b535@id.worldcoin.org",
// if `profile` scope is included:
Expand All @@ -99,4 +104,4 @@ The `/userinfo` endpoint or `id_token` JWT returns a JSON object with the follow

The `sub` field is the user's nullifier hash -- their unique identifier in the context of your app. A user's nullifier hash will be different for each app they use.

You can information about a user's World ID Credentials in the `https://id.worldcoin.org/beta` object. Use the `credential_type` field to determine whether the user has been Orb-verified or not.
You can information about a user's World ID Credentials in the `https://id.worldcoin.org/v1` object. Use the `verification_level` field to determine whether the user has been Orb-verified or not.
57 changes: 57 additions & 0 deletions src/pages/id/verification-levels.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Tag } from '@/components/Tag'
import { Link } from '@/components/Link'

# Verification Levels

The World ID Protocol supports multiple levels of verification, each with a different level of assurance that the user is a unique human.

## Available Verification Levels

This list will continue to grow as more verification levels are supported for proof of personhood in the World ID Protocol.

<table>
<thead>
<tr>
<th>Verification Level</th>
<th>Description</th>
<th>Humanness Level</th>
<th>Availability</th>
</tr>
</thead>
<tbody>
<tr>
<td className="flex items-center"><img src="/icons/credential-phone.svg" alt="" className="h-8 w-8 m-0 mr-2" />Device</td>
<td className="align-middle">Unique device check.</td>
<td className="align-middle">Medium</td>
<td className="align-middle"><Tag color="sky">CLOUD</Tag></td>
</tr>
<tr>
<td className="align-middle"><img src="/icons/credential-orb.svg" alt="" className="h-8 w-8 m-0 mr-2 inline" />Orb</td>
<td className="align-middle">Biometric verification, uniqueness through iris (<Link href="https://worldcoin.org/blog/engineering/opening-orb-look-inside-worldcoin-biometric-imaging-device">details</Link>).</td>
<td className="align-middle">Strong</td>
<td className="align-middle"><Tag>ON-CHAIN</Tag><Tag color="sky">CLOUD</Tag></td>
</tr>
<tr>
<td className="flex items-center"><img src="/icons/credential-face.svg" alt="" className="h-8 w-8 m-0 mr-2" />Orb+</td>
<td className="align-middle">Verify that the same person who visited the Orb is performing a specific action.</td>
<td className="align-middle">Very Strong</td>
<td className="align-middle"><Tag color="zinc">COMING SOON</Tag></td>
</tr>
</tbody>
</table>

### World ID Orb

World ID Orb is the strongest verification level currently available in World ID. It's a biometric verification that relies on the user visiting a World ID Orb, which verifies that the user is a unique human while preserving their privacy.

### World ID Device

World ID Device relies on the user's identity wallet, such as World App, to verify a user's unique device. This is more scalable, user friendly, and privacy-preserving than the previous `phone` credential, which was issued when a user verified their phone number in World App.

## When to use World ID Device vs. Orb

World ID Device offers an assurance that's convenient for a user to obtain, but it also provides a weaker level of resistance to Sybil attacks than World ID's Orb credential. It's best used for applications that only require a moderate level of sybil resistance or have a significant user base in regions where the Orb is not available.

We recommend requiring World ID Orb in instances where users are given a financial incentive, such as a signup bonus or airdrop. For other situations, such as a social media app, it may be sufficient to only require World ID Device. An application can always react according to the verification level used, e.g. when an Orb-verified user performs an action that requires World ID Device.

<Note>Read about configuring IDKit for World ID Device in the [IDKit Reference](/reference/idkit/).</Note>
20 changes: 20 additions & 0 deletions src/pages/id/verify-with-world-id.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Verify with World ID

"Verify with World ID" is the recommended flow for your World ID integration, providing the most flexibility and the least amount of friction for your users.

Users should first create an account with your service, and then verify that account with World ID. This allows for existing users to seamlessly upgrade their account by verifying, and for new users to create an account and verify all at once.

## Integration

"Verify with World ID" can be implemented either with [Sign In with World ID](/id/sign-in) or [Incognito Actions](/id/incognito-actions). The user flow is the same for both, but the implementation is slightly different.

### When to use Sign In with World ID
You should use **Sign In with World ID** if you already allow users to sign in with other identity providers and link multiple accounts together. For example, if a user can sign in to a single account with either an email and password or a Google account, you should use Sign In with World ID.
The user should be able to add Sign In with World ID as a new login method to their existing account, or first create an account with Sign In with World ID and then link other sign in methods to that same account.

<Note>Applications using Auth0 for managing sign in can easily add Sign In with World ID as a new login method. See [Auth0's documentation on User Account Linking](https://auth0.com/docs/manage-users/user-accounts/user-account-linking) and our [Auth0 Integration](https://worldcoin.org/auth0) for more details.</Note>

### When to use Incognito Actions
You should use **Incognito Actions** if you do not want to allow users to sign in using their World ID. In this case, you should use Incognito Actions to verify the user's existing account from a setting menu or prompt them for verification when they first sign in.

<Note>Incognito Actions are very flexible and can be used to verify for multiple one-time actions. Read our [Incognito Actions documentation](/id/incognito-actions) for more details.</Note>
Loading

0 comments on commit 656b4ca

Please sign in to comment.