Laravel Security
Priority: P0 (CRITICAL)
Workflow: Secure a Resource
- Generate policy —
php artisan make:policy PostPolicy --model=Post. - Implement policy methods — Return
boolforview,update,deleteactions. - Authorize in controller — Call
$this->authorize('update', $post). - Add Gate bypass — Define
Gate::before()for admin users inAuthServiceProvider. - Validate inputs — Use Form Request with
$request->validated()forModel::create().
Policy Example
See implementation examples for Policy class with controller authorization.
Implementation Guidelines
Authorization & RBAC
- Policies: Always use
php artisan make:policy PostPolicy --model=Postfor model-level authorization. - Checkers: Implement
update(User $user, Post $post): booland call$this->authorize('update', $post)in controllers. - Gates: Use
Gate::define('admin', fn(User $user) => ...)for global permissions. Check withGate::allows('admin')or Blade@can('admin'). prefer Policies for model-bound checks; use Gates for global permissions. - Admin Bypass: Define
Gate::before(fn($u) => $u->isAdmin() ? true : null)inAuthServiceProvider.
Configuration & Environment
- Environment: Only call env() inside config/*.php files. Access via
config('app.key')in your application code. never env() in controllers; use config() instead. - Caching: Run
php artisan config:cacheto validate thatenv()isn't used where it shouldn't be.
Data & Input Security
- Mass Assignment: Use Form Request with rules() and call $request->validated() for Model::create(). Define $fillable on model; never pass $request->all() to create().
- CSRF: Ensure the @csrf directive is in all Blade
<form>tags. active on web routes by default; use->except(['/webhook'])only for trusted third-party callbacks. - Role-Based Access: Use Policies with role checks in policy methods; define
Gate::beforefor admin bypass; or usespatie/laravel-permission; never inline $user->role === 'admin'.
Anti-Patterns
- No
env()outside config files: Access viaconfig()helper. - No custom auth logic: Use Laravel's built-in auth system.
- No unvalidated mass assignment: Always call
validated(). - No auth logic in Blade: Pass permissions as data from controller.