An API without authentication is like a house without a door. So, let's secure our API by adding an authentication system to it:
- Set up Sanctum Middleware
- Create a User Registration API
- Create a User Login API
Let's get secure!
Setting Up Authentication Middleware
Let's start by securing our API endpoint with a Middleware:
routes/api.php
// ... Route::group(['middleware' => 'auth:sanctum'], function () { Route::apiResource('categories', CategoryController::class); Route::apiResource('transactions', TransactionController::class);});
Now, we can immediately try to make an API request using Postman:
This is good! However, we need to create a user registration and login API to authenticate our users.
Registering our First User
So, let's create a way to register a new user. For this, we need a new Controller:
php artisan make:controller Api/AuthController
In there, let's add a new method to register a user:
app/Http/Controllers/Api/AuthController.php
use App\Models\User;use Illuminate\Http\Request;use Illuminate\Support\Facades\Hash;use Illuminate\Validation\Rules\Password; // ... public function register(Request $request): string{ $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => ['required', 'confirmed', Password::defaults()], 'device_name' => 'required', ]); $user = User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), ]); return $user->createToken($request->device_name)->plainTextToken;}
As you can see, we are doing basic validation and user creation. But in the end, we are trying to create a token for the user. This is where we need to modify our User model:
app/Models/User.php
use Laravel\Sanctum\HasApiTokens; // ... class User extends Authenticatable{ /** @use HasFactory<UserFactory> */ use HasFactory, Notifiable; use HasFactory, Notifiable, HasApiTokens; // ...
Now, let's add a new route for this method:
routes/api.php
use App\Http\Controllers\Api\AuthController; // ... Route::group(['middleware' => 'auth:sanctum'], function () { // ...}); Route::post('/auth/register', [AuthController::class, 'register']);
Now we are ready to make a Postman request to see it in action:
We have received a token back! We can use this token in the Bearer
header to authenticate our requests:
Authenticating our User
The last thing to do is to create a login/logout API endpoint. They both will follow the same pattern as the register method:
app/Http/Controllers/Api/AuthController.php
use Illuminate\Validation\ValidationException; // ... public function login(Request $request): string{ $request->validate([ 'email' => 'required|email', 'password' => 'required', 'device_name' => 'required', ]); $user = User::where('email', $request->email)->first(); if (!$user || !Hash::check($request->password, $user->password)) { throw ValidationException::withMessages([ 'email' => ['The provided credentials are incorrect.'], ]); } return $user->createToken($request->device_name)->plainTextToken;} public function logout(Request $request){ $user = User::where('email', $request->email)->first(); if ($user) { $user->tokens()->delete(); } return response()->noContent();}
And the routes:
routes/api.php
Route::post('/auth/login', [AuthController::class, 'login']);Route::post('/auth/register', [AuthController::class, 'register']);Route::post('/auth/logout', [AuthController::class, 'logout'])->middleware(['auth:sanctum']);
That's it! We can now try to log in using the user we just created:
As you can see, our token starts with 2|
instead of 1|
, which we had previously. This means that we have new token issues for our users.
That's it for our authentication setup. Sanctum is powerful enough that this was all we needed to do to secure our API.
In the next lesson, we will look at a simple multi-tenancy setup for our users. The goal here is for each of our users to manage their own categories and transactions without seeing other users' data.
Check out the GitHub Commit
I would add the sanctum middleware on the logout route. Like this: Route::post('/auth/logout', [AuthController::class, 'logout'])->middleware('auth:sanctum'); . It's more secure.