Wisp – A Modern, Secure One-Time Secret Sharing App Built with Laravel 12, Vue 3 and Inertia.js



This content originally appeared on DEV Community and was authored by Jerome Thayananthajothy

In a world where sensitive data leaks happen daily, sharing passwords, API keys, or confidential information over email or chat is risky.
We’ve all been there — “Can you send me the database password?” and before you know it, it’s stored permanently in Slack history or someone’s inbox.

That’s the problem Wisp solves.

The Solution: Wisp

Wisp is a secure, one-time secret sharing application.
It allows you to send encrypted secrets via unique links that expire after being viewed or after a set period of time, after which they are permanently deleted.

Key highlights:

  • Secrets are encrypted using AES-256-CBC before storage
  • Optional password protection
  • Links auto-expire after minutes, hours, or days
  • Secrets are deleted permanently after first viewing
  • No decrypted secret is ever stored server-side

Wisp New Secret Form

Technical Deep-Dive

Wisp is built with a stack that prioritizes security, developer productivity, and a modern user experience.

Backend

  • Laravel 12.21 with PHP 8.4
  • Laravel’s AES-256-CBC encryption
  • Bcrypt password hashing
  • MySQL 8.0+
  • PHPUnit for backend tests

Frontend

  • Vue 3.5 (Composition API) with TypeScript
  • Inertia.js 2.0 for seamless Laravel-Vue integration
  • Tailwind CSS 3.4 with shadcn/ui for consistent UI components
  • Ziggy for Laravel routes in JavaScript

Hosting

  • Deployed on Heroku with HTTPS enforced

Security Implementation

Wisp’s core principle: encrypt sensitive data immediately, destroy it quickly, and never store it in plain text.

How it works:

  1. Secrets are encrypted with AES-256-CBC before saving to the database.
  2. If a password is set, it is hashed using Bcrypt and verified before decryption.
  3. On first view, the secret is permanently deleted.
  4. If not viewed, it is automatically removed at the set expiration time.
// Laravel encryption example
$encrypted = encrypt($secretContent);
$decrypted = decrypt($encrypted);

Wisp Password Protected View

Why Inertia.js?

Instead of building a traditional API with a separate frontend, Wisp uses Inertia.js to connect Laravel and Vue directly.

Benefits:

  • No need for API controllers or serialization layers
  • Laravel handles routing and authentication natively
  • SPA experience without managing a separate API stack

Example Inertia route in Laravel:

Route::get('/secrets/create', function () {
    return Inertia::render('Secrets/Create');
})->name('secrets.create');

Wisp Secret View with Deletion Notice

Developer Experience

  • Laravel Pint for automatic code formatting
  • Nightwatch.js for end-to-end testing of the secret sharing flow
  • Full TypeScript support for frontend predictability
  • shadcn/ui for accessible and reusable components

Installation

Clone the repository:

git clone https://github.com/Thavarshan/wisp.git
cd wisp

Install dependencies:

composer install
npm install

Configure environment:

cp .env.example .env
php artisan key:generate

Run migrations:

php artisan migrate

Start the application:

php artisan serve
npm run dev

Usage

  1. Visit / and create a new secret
  2. Set an optional password and expiration time
  3. Share the generated link
  4. Once opened, the secret is permanently deleted

Wisp Secret View with Deletion Notice

Contributing

Wisp is open-source and welcomes contributions.

Call to Action

If you’ve ever sent a password over chat and worried about where it might end up, Wisp is for you.
Try it out, give it a star on GitHub, and help improve it. Together, we can make secure sharing the default.


This content originally appeared on DEV Community and was authored by Jerome Thayananthajothy