janecodelife / livewire-secure-properties
Automatically lock Livewire properties from client-side modification unless explicitly unlocked with zero configs.
Package info
github.com/janecodelife/livewire-secure-properties
pkg:composer/janecodelife/livewire-secure-properties
Fund package maintenance!
Requires
- livewire/livewire: ^4.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
🔒 Livewire Secure Properties 🔒
An elegant, zero-configuration security package for Laravel Livewire 4 that automatically locks all public component properties from client-side manipulation, unless explicitly marked as unlocked.
✅ Auto-lock properties
✅ Zero configuration
✅ Protects against client-side tampering
✅ Unlock specific properties with #[Unlocked]
✅ Supports Livewire 4 (Single & Multiple File)
💡💡 Imagine These Scenarios (Use Cases) 💡💡
🕵️♂️ Scenario 1: Account ID Spoofing Or In Details Pages Or In Multiple Step Form
Imagine a multi-step multi-tenant onboarding wizard where you pass a public identifier to keep track of the account being edited:
public int $accountId = 45; public int $formStep = 1;
The Risk: The user alters the $accountId in their browser from 45 to 46, allowing them to view or overwrite data belonging to an entirely different customer or tenant.
The Solution: Since you did not add the #[Unlocked] attribute to $accountId, it is strictly bulletproof. The front-end cannot mutate this state between requests, effortlessly closing broken object-level authorization (BOLA) vulnerabilities without you writing a single line of defensive boilerplate code.
🌍 Scenario 2: Cascading Dropdowns & Relational Tampering (Country ➔ State ➔ City)
Imagine you are building a registration form with cascading dropdowns where selecting a Country loads its States, and selecting a State loads its Cities:
public int $countryId; // ✅ Secured: Locked by default public int $stateId; // ✅ Secured: Locked by default (Crucial!) public int $cityId; // ✅ Secured: Locked by default
The Risk: If you leave $stateId or $countryId open/unlocked (#[Unlocked]), a malicious user can easily open browser DevTools. They could select a valid State and City for Germany, but manually alter the $stateId or $countryId payload to point to IDs in the USA right before submitting. This bypasses your frontend UI logic and injects corrupted, mismatched relational data into your database (e.g., a user saved with Country: USA, State: Berlin, City: Munich).
The Solution: By leaving the entire chain locked, you force the state mutation to happen safely via secure backend methods (using wire:change instead of direct wire:model). The client cannot forge or desynchronize any parent-child relational IDs, automatically guaranteeing 100% data integrity across your entire cascading chain.
Requirements
- Livewire ^4.0
Installation
You can install the package via composer:
composer require janecodelife/livewire-secure-properties
Usage
1. Single File Components (SFC)
If you are using Livewire 4's native Single File Components layout, you can safely use the #[Unlocked] attribute inside the anonymous class block:
<?php use Livewire\Component; use JaneCodeLife\LivewireSecureProperties\Unlocked; new class extends Component { // ✅ Secured: Locked by default, any client-side update will throw a Security Violation exception public string $role = 'admin'; // 🔓 UNLOCKED: Updatable from client side via wire:model or client-side requests #[Unlocked] public string $name = 'Jane Joe'; }; ?> <div> <input type="text" wire:model.live="name"> <p>Name: {{ $name }}</p> <!-- This would securely block any client-side update attempts --> <input type="text" wire:model.live="role"> <p>Role: {{ $role }}</p> </div>
2. Multiple File Components (Class-based)
use Livewire\Component; use JaneCodeLife\LivewireSecureProperties\Unlocked; class UserProfile extends Component { // ✅ Secured: Locked by default, any client-side update will throw a Security Violation exception public string $role = 'admin'; // 🔓 UNLOCKED: Updatable from client side via wire:model or client-side requests #[Unlocked] public string $name = 'Jane Joe'; public function render() { return view('livewire.user-profile'); } }
Video 📺
Configuration
If you need to disable the package globally during specific environments (e.g., local debugging), you can add this environment variable to your .env file:
LIVEWIRE_SECURE_PROPERTIES_ENABLED=false
Security Violations
When a locked property is violated, the package throws a PropertyLockedException with a 403 status code, making it easy to intercept globally or monitor via your error loggers.
💝🤟 Support the Project 🤟💝
Every bit of support fuels the expansion of this ecosystem and helps me write cleaner tools for all of us. Thank you for standing behind independent developers!_ 🙏🤟
💝🤟 A huge thank you to our sponsors! 💝🤟
🔗 My Other Plugins
Check out my other open-source tools to supercharge your Neovim environment:
- livewire-secure-properties - Secure livewire app properties by default and void headache.
- todo-tracker.nvim - Assign and list app todos in a blink
- folders-bookmark.nvim - Bookmark folders and accessing them by keymap in a blink
- copy-history.nvim - Access your copy (Yank) history and paste it again with support of edit by 1 click in a blink.
- rest-client.nvim - run http request from anywhere in a blink
- smart-window-focus.nvim - resize split window on focus to be full size to easy to see and debug.
- markdown-toc.nvim - access markdown file headings (Table Of Content)
- tiny-textobject.nvim - handle text objects (inner/around) without need for Tree-sitter.
If Have A Question 🤝 (Contact Me) 🤟
I will be there to answer to all messages
- X (Twitter): https://x.com/janecodelife
- YouTube: https://www.youtube.com/@JaneCodeLife
- Email: janecodelife@gmail.com

