Inspiration
Every time you verify your age online, you expose your photo ID to another potential database breach. This year alone, hackers breached Discord's identity verification provider and exposed government ID images from ~70,000 users. Tea App left their storage bucket open, leaking over 13,000 verification selfies and nearly 60,000 driver's licenses.
The question: How do we verify age without shipping your sensitive documents to every company that asks?
S1ngleID is a privacy-first identity layer that proves you're 19+ without exposing your ID to anyone else.
What it does
Users upload their ID once to verify their age. We create a credential certifying they're 19+ and bind it to their Face ID, fingerprint or device passkey. This credential can't be transferred, sold, or stolen. It enables secure, regulation-compliant age verification for any app or website without exposing personally identifiable information.
Major features are: OCR ID data extraction with Tesseract and OpenCV, zero-storage architecture (your photo ID is never permanently stored), WebAuthn passwordless authentication
How we built it
We built the full stack with Next.js 14. The frontend is React with TypeScript. Backend API routes run on Next.js. PostgreSQL database managed through Prisma. Local development uses Docker for PostgreSQL.
Challenges we ran into
None of us had used this tech stack before. Refining the Tesseract OCR and OpenCV raw text output to extract ID required information fields was tricky. Understanding WebAuthn's passwordless authentication flow and figuring out how to balance fraud prevention with privacy guarantees was the steepest learning curve.
Accomplishments that we're proud of
It actually works lmao
What we learned
New tech stack, new authentication flows, and how to build zero-storage architecture. We learned that perfect fraud prevention at scale is hard. The key is being honest about limitations to your users while building the strongest system you can.
What's next for S1ngleID
Age range proofs with Merkle trees: Right now, S1ngleID is binary, you're either 19+ or you're not. But different services need different thresholds (Discord wants 13+, getting a G1 wants 16+, buying alcohol wants 19+). With Merkle trees, we can build a single credential during initial verification that supports selective disclosure for any age threshold. You can prove you're 13+ to Discord without revealing you're old enough to drink. Your age, and other information, remain disclosed.
Built With
- docker
- next.js
- opencv
- postgresql
- prisma
- react.js
- tesseract
- typescript
- webauthn
Log in or sign up for Devpost to join the conversation.