Task Manager: Securing the Application with User-Scoped Data
Learn how to secure your Laravel Task Manager by associating tasks with users and filtering data so users can only view and manage their own personal tasks.
Previously in this course, we explored Introduction to Authentication: Securing Your Laravel Application to handle logins and session management. Now that your users can sign in, we need to ensure they aren't seeing or editing each other's work.
In this lesson, we will implement user-scoped data. This is the final step in moving from a shared, public list to a private, secure Task Manager.
Adding User Ownership to Tasks
Right now, our tasks table is agnostic—any task exists for anyone. To fix this, we need to establish a relationship between our User model and our Task model.
1. Update the Database Schema
First, we need to add a user_id column to our tasks table. If you've been following along with Task Manager: Displaying Real Database Records, you already have a migration file. Create a new migration to add the column:
Bashphp artisan make:migration add_user_id_to_tasks_table --table=tasks
In the new migration file, add the column:
PHPpublic function up() { Schema::table('tasks', function (Blueprint $table) { $table->foreignId('user_id')->constrained()->onDelete('cascade'); }); }
Running php artisan migrate updates our schema. By using constrained(), Laravel automatically assumes a foreign key relationship to the users table. The onDelete('cascade') ensures that if a user deletes their account, their tasks are automatically removed as well.
2. Associate Tasks with the Authenticated User
When creating a new task, we must capture the current user's ID. In your TasksController, you shouldn't rely on hidden form inputs (which can be spoofed). Instead, use the auth() helper.
PHPpublic function store(Request $request) { $validated = $request->validate([ 'title' => 'required|max:255', ]); #6A9955">// Associate the task with the logged-in user $request->user()->tasks()->create($validated); return redirect('/tasks'); }
By calling $request->user()->tasks()->create(...), Laravel automatically assigns the user_id of the authenticated user to the new record.
Filtering Tasks by User ID
Now that our database records have owners, we must update our index logic to hide data that doesn't belong to the current user.
Updating the Controller
In your TasksController@index method, instead of Task::all(), we filter by the authenticated user:
PHPpublic function index() { #6A9955">// Retrieve only tasks belonging to the authenticated user $tasks = auth()->user()->tasks; return view('tasks.index', ['tasks' => $tasks]); }
If a user tries to access a task ID that doesn't belong to them (e.g., via a direct URL), they shouldn't see it. We will cover how to prevent unauthorized access to specific records using policies and route model binding in the next few lessons, but filtering the collection is the essential first step.
Hands-on Exercise
- Run the migration to add the
user_idcolumn. - Update your existing tasks: Since your current database records don't have a
user_id, update them in the database or truncate the table so you can start fresh with associated tasks. - Test the flow: Log in as User A, create a task, then log out and log in as User B. Ensure User B does not see the task created by User A.
Common Pitfalls
- The "Mass Assignment" Trap: Remember to add
user_idto the$fillablearray in yourTaskmodel if you are using mass assignment. However, when using the$user->tasks()->create()pattern, Laravel handles theuser_idassignment safely for you. - The "N+1" Query Problem: When you start linking users to tasks, you might accidentally trigger multiple database queries. Keep an eye on your debug bar; we will look at how to optimize this with eager loading in later lessons.
- Missing Foreign Key Constraints: Always use
constrained()in migrations. It ensures database integrity, preventing "orphaned" tasks that point to non-existent users.
Recap
We have successfully secured our application by:
- Adding a
user_idcolumn to ourtaskstable. - Using the
auth()->user()helper to associate new tasks with the logged-in user. - Scoping our index query to
auth()->user()->tasksso that data is private to the user.
Your Task Manager is now a truly personal application.
Up next: We'll dive into Route Model Binding to simplify how we retrieve and protect specific task records.
Work with me

FilamentPHP Admin Panel & Dashboard Development
A powerful admin panel for your Laravel app — built with FilamentPHP so you can manage everything without touching the database.

Laravel REST API Development
Clean, secure, well-documented Laravel REST APIs — the backend engine for your app, mobile client, or SaaS. Built by an API specialist.