DEV Community

Cover image for FadeKey: zero-knowledge, self-destructing secret sharing engine
Julian Geiger Nunes
Julian Geiger Nunes

Posted on

FadeKey: zero-knowledge, self-destructing secret sharing engine

GitHub “Finish-Up-A-Thon” Challenge Submission

This is a submission for the GitHub Finish-Up-A-Thon Challenge

What I Built

FadeKey is a zero-knowledge, self-destructing secret sharing engine. Encrypted entirely in the browser using AES-GCM, the decryption key resides only in the URL hash fragment (#key=...). Since browsers do not send the hash fragment in HTTP requests, the server never sees the key or plaintext.
The project is divided into two distinct components:

  • Public Open-Source Core: A standalone, stateless Fastify API and SDK package for self-hosting and automation via pipelines/CLI.

* Private SaaS Dashboard: A commercial-grade Nuxt 4 web app that adds user accounts, Postgres database sync, persistent audit logs, and Stripe subscription control.

Demo


The Comeback Story

We resurrected an unfinished prototype that had major security flaws, incomplete features, and a leaking state. Here is our before-and-after journey:

1. Active Revocation (SDK & API Core)

  • Before: Secrets could only expire via TTL or view limits. The backend lacked a deletion endpoint, and the @fadekey/sdk had an empty placeholder where revoke() should have been.
  • After: We built a secure DELETE /api/items/:id route in the Fastify API (with owner verification checks) and implemented the corresponding revoke(id) method in the SDK package. ### 2. Zero-Knowledge Compliance for QR Codes (UX/Security)
  • Before: The prototype suggested using external public APIs to generate QR codes. However, sending the full secret URL (containing the #key hash) to a third-party server violates zero-knowledge compliance.
  • After: We moved 100% of the QR code generation to the browser using local client-side rendering with the qrcode library, ensuring the decryption key never leaves the client. ### 3. Local-to-Cloud Preference Syncing
  • Before: Users lost their theme (dark/light) and locale (en/es/pt-BR) settings upon page reload, and there was no way to persist these preferences for registered users.
  • After: We built a dual-persistence system. Anonymous users store preferences in cookies/localStorage, while authenticated users sync their choices automatically to a PostgreSQL database via a new PATCH /api/auth/preferences endpoint. ### 4. Critical Nuxt SSR Session Leaks (Major Bugfix)
  • Before: The authentication state was stored in a global reactive singleton. During Server-Side Rendering (SSR), this leaked the session/token of one user to subsequent requests from completely different visitors, causing security risks and hydration errors.
  • After: We refactored the auth composable to store sessions in request-isolated Nuxt useState wrappers, guaranteeing sandboxed memory for every client. ### 5. Transition Polish & Redirection Guarding
  • Before: Logging out caused dashboard pages to immediately display blank values and zeroes before redirecting. Redirections also dropped the active language prefix (e.g. redirecting /pt-BR/app/dashboard to / instead of /pt-BR).

* After: We deferred state destruction in signOut() until after the router navigation completes, backed by a nextTick + 150ms delay in router.afterEach to allow the DOM to mount. We wrapped all redirects in localePath() to ensure language consistency.

My Experience with GitHub Copilot

GitHub Copilot acted as a core partner during this sprint, particularly in:

  1. Refactoring Auth for SSR Safety: Copilot recognized the risks of our initial module-level singleton state in Nuxt and drafted the migration to request-scoped useState hooks, pointing out how to avoid server-side data pollution.
  2. Writing Vitest Suites with Testcontainers: It accelerated the creation of our backend integration tests, generating mock Postgres databases and Redis instances using Docker Testcontainers to test rate-limiting and quota rollback scenarios.
  3. Client-side Encryption Pipelines: Copilot assisted in structuring the Web Crypto API calls in our SDK to correctly derive password hashes using PBKDF2 without introducing synchronous blocking.

Top comments (1)

Collapse
 
larissa_martinsgonalves profile image
Larissa Martins Gonçalves

Parabéns Julian!

devchallenge

githubchallenge

GitHub “Finish-Up-A-Thon” Challenge Submission