Skip to main content
Login with Billions and credential verification run on the same protocol. Your app asks, the user’s wallet answers with a signed token, and your backend checks it.

The parties

The flow

1

Your backend creates an authorization request

It names your verifier DID, a reason shown to the user, and a callback URL that includes a session ID. Your backend stores the request so it can check the answer later.
2

The user opens it in the wallet

Your frontend Base64-encodes the request into a Universal Link that opens the Billions Wallet. The wallet shows the user what’s being asked.
3

The wallet answers with a signed token

If the user approves, the wallet signs a JWZ (JSON Web Zero-knowledge) token. For a credential request, it also generates a zero-knowledge proof against the credential.
4

The wallet posts the token to your callback

The token arrives at your callback URL, tagged with the session ID.
5

Your backend verifies it

It verifies the token against the stored request. The verified response gives you the user’s DID and, for a credential request, the proof.

Login versus credential verification

Stopping repeat claims

A credential proof carries a nullifier: a privacy-preserving identifier derived from the person’s identity and a nullifierSessionId that your app chooses for a campaign. Keep that value fixed and the same person always produces the same nullifier, so you can record the nullifiers you accept and refuse repeats, even from a different account. Use a different value for a different campaign and the same person’s nullifiers can’t be linked between them. Each request still gets its own session ID, which ties the wallet’s answer to that request. This is what makes one-reward-per-person possible without learning who anyone is.