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
- Live Site (Private SaaS): https://fadekey.app
- GitHub Repository (Open-Source Core): https://github.com/fadekey-app/fadekey.api
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/sdkhad an empty placeholder whererevoke()should have been. - After: We built a secure
DELETE /api/items/:idroute in the Fastify API (with owner verification checks) and implemented the correspondingrevoke(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
#keyhash) 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
qrcodelibrary, 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/preferencesendpoint. ### 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
useStatewrappers, 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/dashboardto/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:
- 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
useStatehooks, pointing out how to avoid server-side data pollution. - 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.
- 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)
Parabéns Julian!
devchallenge
githubchallenge
GitHub “Finish-Up-A-Thon” Challenge Submission