Minimal full-stack example showing how to:
- Display a Self QR code in a web app.
- Verify proofs on a Rust backend (which calls a minimal Node worker using
@selfxyz/core) with mock passports and OFAC checking. - Inspect the full verification result.
client/– Next.js frontend- Renders the QR code using
@selfxyz/qrcode. - Calls the backend verify endpoint and shows the verification JSON.
- Renders the QR code using
server/– Rust backend + Node workerCargo.toml/src/main.rs– Rust HTTP server exposing:POST /api/verifyGET /debug/last-result
worker/– Node worker project:worker/worker.mjs– usesSelfBackendVerifierfrom@selfxyz/core.worker/package.json– Node deps for the worker only.- Configured for staging/mock passports with OFAC enabled and minimum age 18.
- Node.js 18+ (Self SDK recommends Node 22; you may see engine warnings on other versions, but it still runs).
- npm (comes with Node).
Install dependencies once:
# Node worker deps
cd server/worker
npm install
# Frontend deps
cd ../../client
npm install
# Build Rust backend (from repo root)
cd ..
cargo build --manifest-path server/Cargo.tomlBuild the Rust backend once (from the repo root):
cargo buildCreate server/.env in the server/ folder:
PORT=3001
SELF_SCOPE=demo1-scope
SELF_ENDPOINT=https://your-ngrok-id.ngrok-free.app/api/verifyPORT– local port for the Rust backend.SELF_SCOPE– must match the frontendNEXT_PUBLIC_SELF_SCOPE.SELF_ENDPOINT– public URL for/api/verify(typically an ngrok URL pointing to your local backend).
Create client/.env.local:
NEXT_PUBLIC_SELF_APP_NAME=Self Verification Demo
NEXT_PUBLIC_SELF_SCOPE=demo1-scope
NEXT_PUBLIC_SELF_ENDPOINT=https://your-ngrok-id.ngrok-free.app/api/verify
NEXT_PUBLIC_SELF_DEBUG_ENDPOINT=http://localhost:3001/debug/last-resultNEXT_PUBLIC_SELF_SCOPEmust equalSELF_SCOPE.NEXT_PUBLIC_SELF_ENDPOINTmust equalSELF_ENDPOINT.NEXT_PUBLIC_SELF_DEBUG_ENDPOINTpoints directly to the local debug endpoint to read the last verification result.
- The frontend (
client/) builds aSelfAppviaSelfAppBuilderand renders a QR code withSelfQRcodeWrapper. When the Self mobile app scans and completes verification, it calls the backendPOST /api/verifyendpoint with the proof. - The Rust backend (
src/main.rs) is the only HTTP server. It exposes:GET /– basic status/config info.POST /api/verify– validates the payload and forwards it to a Node worker.GET /debug/last-result– returns the lastVerificationResult(for inspection in the UI).
- The Node worker (
server/worker.mjs) runs as a child process managed by the Rust cratenode-workers:- It listens on stdin/stdout using a simple line-based protocol (READY, PAYLOAD_CHUNK, RESULT_CHUNK, OK).
- It constructs
SelfBackendVerifierwith:scopefromSELF_SCOPEendpointfromSELF_ENDPOINTmockPassport = trueAllIdsandDefaultConfigStorewith minimum age 18, OFAC enabled.
- It exposes a single command,
verifyProof, which callsselfBackendVerifier.verify(...)and returns theVerificationResultJSON back to Rust.
On the Rust side, node-workers maintains a pool of long-lived Node worker processes so subsequent verifications don’t pay the cost of booting Node each time.
-
Start the backend (Rust)
cd server cargo run- Listens on
http://localhost:3001by default (controlled byPORT). - Endpoints:
POST /api/verify– main verification endpoint.GET /debug/last-result– returns the last verification result (for the frontend).
- Listens on
-
Expose the backend to Self (optional, for real device testing)
ngrok http 3001
- Use the ngrok URL (e.g.
https://xxxx.ngrok-free.app/api/verify) in both:SELF_ENDPOINTNEXT_PUBLIC_SELF_ENDPOINT
- Use the ngrok URL (e.g.
-
Start the frontend
cd client npm run dev- Visit
http://localhost:3000in your browser.
- Visit
-
Verify with the Self app
- Open the Self app (staging), ensure you’re using a mock passport (see
self-docs/using-mock-passports.md). - Scan the QR code from the frontend.
- After verification:
- The QR disappears.
- The full
VerificationResultis shown as JSON below, including:attestationIdisValidDetails(overall, age, OFAC)discloseOutput(nationality, gender, etc.)userData(userIdentifier + userDefinedData).
- Open the Self app (staging), ensure you’re using a mock passport (see
