1. Abstract
This spec lets Authenticators disclose a nullifier more than once, but only to Relying Parties (RPs) that the Authenticator Provider whitelists. A whitelisted RP can then use the nullifier as a uniqueness identifier: a stable per-user account key that both enforces one account per user and recognizes a returning user, for example to authenticate them, from a single Uniqueness Proof.
2. Motivation
RPs that need to use World ID for authentication require a stable per-user identifier that every Authenticator can reproduce without client state. The nullifier already is one: it is deterministic in (leaf_index, rp_id, action) and bound to the user by the Uniqueness Proof. Authenticators refuse to disclose it twice, so today an RP can’t use it to log a user in again. They refuse because a nullifier disclosed repeatedly becomes a pseudonymous identifier that links all of a user’s proofs to the same RP, which is dangerous for standard RPs.
The protocol doesn’t enforce one-time use. Contracts don’t store nullifiers and OPRF Nodes don’t track them. Each Authenticator keeps a local replay guard, which other Authenticators of the same World ID don’t share. Users therefore already trust their Authenticator Provider to keep nullifiers one-time use. That trust can also cover a small set of RPs the provider lets reuse them.
3. Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
3.1 Proof Request
The ProofRequest and ProofResponse formats are unchanged. A whitelisted RP requests a reusable nullifier with a standard uniqueness request.
3.2 RP Whitelist
- Authenticators MUST only disclose a nullifier more than once to RPs that are explicitly whitelisted by the Authenticator Provider. The distribution of this whitelist is out of scope and up to the Authenticator Provider. It could e.g. be distributed as part of an app release.
- Authenticators MUST be transparent about the members of the whitelist and SHOULD allow users to remove RPs from the whitelist they do not trust.
- Authenticators MUST NOT let users add RPs to the whitelist without a warning that the RP will be able to recognize them.
- When handling a request from a whitelisted RP, Authenticators MUST show a distinct UI that tells the user the RP can recognize them. They MUST NOT present the proof as anonymous.
3.3 Authenticator Flow
- The Authenticator runs the nullifier query for every request. It MUST NOT reuse a cached OPRF output unless it verifies the RP signature and request expiry itself, because otherwise only OPRF Nodes check them (see §5).
- If the RP is not whitelisted, the Authenticator MUST refuse a nullifier it already disclosed.
- If the RP is whitelisted, the Authenticator skips the replay guard check and builds the proof.
- The Authenticator SHOULD record the nullifier in the replay guard for whitelisted RPs too, so that removing an RP from the whitelist makes its nullifiers one-time use again.
3.4 RP Guidance
- Uniqueness identifier. A whitelisted RP MAY use the nullifier as a uniqueness identifier, i.e. as the key of the user’s account. The value and the
nullifierfield are unchanged; the term only names this use. - Registration and authentication. The RP sends a
uniquenessrequest with a fixedaction. If the uniqueness identifier is unknown, it creates an account under it. If it is known, it logs the user into that account. One request covers both cases. - Nonce. The RP MUST check that the proof’s
nonceis the one it issued for this login and MUST NOT accept a nonce twice. Otherwise a captured proof logs in anyone who replays it. - Action choice. The RP SHOULD keep one fixed
actionper purpose. Changing the action gives every user a new uniqueness identifier. - Non-whitelisted Authenticators. An RP MUST NOT assume every Authenticator whitelists it. A user whose Authenticator doesn’t whitelist the RP can register but can’t log in again with a Uniqueness Proof.
4. Rationale
- Reuse the nullifier instead of a new identifier. The nullifier is already deterministic across Authenticators and bound to the user by the circuit. The
id_commitmentof a seeded session isn’t proven to derive from the seed, so it needs a Uniqueness Proof next to it for sybil resistance. A reusable nullifier gives both in one proof. - One request, one round trip. Seeded sessions need a uniqueness request to register and a session request to authenticate, and bound uniqueness proofs add a proof type to merge them. Here the RP always sends the same
uniquenessrequest. - No wire format change. RPs, OPRF Nodes, contracts and circuits stay unchanged. Only Authenticators change their replay guard.
- Naming. A nullifier is the value a verifier records to void a one-time right. That still describes its use for duplicate checks, but not for authentication, where nothing is voided. This spec keeps the
nullifierfield and names the authentication use “uniqueness identifier”. Renaming the field would touch circuits, contracts, SDKs and RP integrations, and would suggest two different values.
5. Security
- Tracking within an RP. A uniqueness identifier is a stable per-RP identifier. All Uniqueness Proofs a user gives a whitelisted RP for one
actionare linkable. This is why §3.2 requires a whitelist and a distinct UI. Nullifiers for different RPs stay unlinkable. - The whitelist is enforced by Authenticators only. It protects users from RPs. A modified Authenticator that ignores it only exposes its own user.
- Proof replay. A proof works as a login credential for a whitelisted RP. The RP’s nonce check (§3.4) is what stops replays.
- OPRF key rotation for an RP changes all of its nullifiers, and users lose access to their accounts.
- Forged requests. The nonce is not bound to the OPRF output, so a cached output yields a valid proof for any request. Without the RP signature check, a party impersonating a whitelisted RP would learn the user’s uniqueness identifier for that RP. Logging in still needs a nonce issued by the RP (§3.4).
6. Backwards Compatibility
The change is additive. Authenticators that don’t implement this spec refuse the second request as a replay. RPs, OPRF Nodes, contracts and circuits need no changes. The World ID 4.0 spec statement that Authenticators never disclose a nullifier more than once becomes: except to whitelisted RPs.