# ๐ Lecture 8: Authentication with Laravel Sanctum
> Duration: \~3 hours\
> Target: Beginner to Intermediate\
> Stack: Laravel 12, RESTful APIs, Sanctum\
> Context: Using our **Expert Platform** backend APIs
---
## ๐ Objectives
By the end of this lecture, trainees will:
- Understand **what authentication and authorization** mean in APIs
- Learn **what tokens and API keys** are
- Use **Laravel Sanctum** to secure APIs
- Implement **registration**, **login**, and **logout** endpoints
- Protect existing endpoints like `/api/experts` and `/api/bookings`
- Build an authenticated `/api/me` route to get user info
---
## ๐ง Theory: What is Authentication & Authorization?
| Concept | Explanation |
| ------------------ | -------------------------------------------------------------------------------------------------------------------- |
| **Authentication** | Who are you? Proving your identity via credentials (email/password). |
| **Authorization** | What can you do? Checking if you're allowed to access certain resources. |
| **Access Token** | A secret key given after login, used to access protected APIs. |
| **API Key** | A static token (not tied to login) used by clients to identify themselves. We use **access tokens** in this lecture. |
### ๐งน Sanctum vs Passport
Laravel has two main options for API auth:
- **Sanctum** (simple token-based, great for SPAs, mobile, basic APIs โ
)
- **Passport** (full OAuth2 server, more complex โ for now)
๐ข We use **Sanctum** because it's lightweight, easy, and perfect for our **Expert Platform**.
---
## ๐งช Step 1: Install Sanctum
```bash
composer require laravel/sanctum
```
Then publish Sanctum's config and migration:
```bash
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
```
This creates a new table: `personal_access_tokens`.
---
## โ๏ธ Step 2: Configure Sanctum
In `app/Http/Kernel.php`, add middleware:
```php
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
```
Then in `config/sanctum.php`:
```php
// leave as default for now
```
---
## ๐ค Step 3: Prepare the `User` Model
Open `app/Models/User.php` and add the `HasApiTokens` trait:
```php
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
```
---
## โ๏ธ Step 4: Create Auth Controller
```bash
php artisan make:controller Api/AuthController
```
Inside `app/Http/Controllers/Api/AuthController.php`:
```php
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
class AuthController extends Controller
{
public function register(Request $request)
{
$fields = $request->validate([
'name' => 'required|string',
'email' => 'required|string|email|unique:users,email',
'password' => 'required|string|confirmed',
]);
$user = User::create([
'name' => $fields['name'],
'email' => $fields['email'],
'password' => bcrypt($fields['password']),
]);
$token = $user->createToken('expert-platform-token')->plainTextToken;
return response()->json([
'user' => $user,
'token' => $token,
], 201);
}
public function login(Request $request)
{
$fields = $request->validate([
'email' => 'required|string|email',
'password' => 'required|string',
]);
$user = User::where('email', $fields['email'])->first();
if (!$user || !Hash::check($fields['password'], $user->password)) {
throw ValidationException::withMessages([
'email' => ['The credentials are incorrect'],
]);
}
$token = $user->createToken('expert-platform-token')->plainTextToken;
return response()->json([
'user' => $user,
'token' => $token,
]);
}
public function logout(Request $request)
{
$request->user()->tokens()->delete();
return response()->json(['message' => 'Logged out']);
}
public function me(Request $request)
{
return response()->json($request->user());
}
}
```
---
## ๐ Step 5: Register Auth Routes
In `routes/api.php`:
```php
use App\Http\Controllers\Api\AuthController;
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
Route::middleware('auth:sanctum')->group(function () {
Route::post('/logout', [AuthController::class, 'logout']);
Route::get('/me', [AuthController::class, 'me']);
});
```
---
## ๐ Step 6: Protect Existing APIs
For example, in your `routes/api.php`:
```php
use App\Http\Controllers\Api\ExpertController;
Route::middleware('auth:sanctum')->group(function () {
Route::apiResource('/experts', ExpertController::class);
Route::post('/bookings', [BookingController::class, 'store']);
// more protected routes...
});
```
Now, users must be logged in and send `Authorization: Bearer <token>` header.
---
## ๐ Step 7: Testing with Postman
1. **Register:**
```http
POST /api/register
Content-Type: application/json
{
"name": "John Doe",
"email": "john@example.com",
"password": "password",
"password_confirmation": "password"
}
```
2. **Login:**
```http
POST /api/login
```
โ Copy `token` from response
3. **Call protected route:**
```http
GET /api/me
Authorization: Bearer eyJ0eXAiOiJKV...
```
---
## ๐ผ๏ธ [Diagram] Sanctum Flow
```
+-------------+ POST /login +----------------------+
| Frontend +--------------------->+ AuthController |
+-------------+ +----------------------+
|
| -> Validates credentials
| -> Generates token
| <- Returns token
v
+-------------+ GET /experts +----------------------+
| Postman +------------------->+ Protected Controller |
| (with token) | Authorization +----------------------+
+-------------+ Bearer token
```
---
## ๐ฏ Summary
- Authentication = verifying identity
- Sanctum = simple token-based auth for APIs
- `HasApiTokens` enables `createToken()` method
- Routes protected via `auth:sanctum`
- Tokens sent via HTTP `Authorization` header
---
## ๐ Assignment
> ๐ Secure your `/api/experts` and `/api/bookings` endpoints:
1. Implement `/api/register`, `/api/login`, `/api/logout`
2. Add `/api/me` to return logged-in user
3. Protect expert and booking routes with `auth:sanctum`
4. Test all endpoints using Postman