"Pernah nggak, frontend kamu butuh data dari backend Laravel, tapi API-nya belum aman? Di artikel ini, kamu akan belajar bikin API CRUD yang hanya bisa diakses user terautentikasi pakai Sanctum."
Kenapa Harus Pakai Sanctum untuk API CRUD?
- Data lebih aman, hanya user login yang bisa akses
- Cocok untuk SPA, mobile app, dan aplikasi modern
- Mudah diintegrasikan dengan frontend (React, Vue, dsb)
Studi Kasus: API Artikel (CRUD + Auth)
Kita akan membuat API CRUD Artikel yang hanya bisa diakses user yang sudah login menggunakan Laravel Sanctum.
Step 1: Setup Project Laravel & Sanctum
composer create-project --prefer-dist laravel/laravel belajar-api
cd belajar-api
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
Tambahkan middleware Sanctum di app/Http/Kernel.php pada group api:
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
Step 2: Setup Model User & Artikel (Ownership Data)
User
Pastikan model User pakai trait HasApiTokens dan relasi ke artikel:
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
// ...
public function articles() {
return $this->hasMany(Article::class);
}
}
Artikel
php artisan make:model Article -m
Edit migration:
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->timestamps();
});
}
Jalankan migrasi:
php artisan migrate
Di model Article.php:
protected $fillable = ['title', 'content', 'user_id'];
public function user() {
return $this->belongsTo(User::class);
}
Step 3: Auth Controller (Register, Login, Logout)
php artisan make:controller Api/AuthController
Contoh fungsi register, login, logout:
public function register(Request $request) {
$validated = $request->validate([
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|min:6',
]);
$user = User::create([
'name' => $validated['name'],
'email' => $validated['email'],
'password' => bcrypt($validated['password']),
]);
$token = $user->createToken('api-token')->plainTextToken;
return response()->json(['user' => $user, 'token' => $token], 201);
}
public function login(Request $request) {
$credentials = $request->only('email', 'password');
if (!auth()->attempt($credentials)) {
return response()->json(['message' => 'Unauthorized'], 401);
}
$user = auth()->user();
$user->tokens()->delete();
$token = $user->createToken('api-token')->plainTextToken;
return response()->json(['user' => $user, 'token' => $token]);
}
public function logout(Request $request) {
$request->user()->currentAccessToken()->delete();
return response()->json(['message' => 'Logged out']);
}
Step 4: Article Controller (CRUD)
php artisan make:controller Api/ArticleController --resource
Contoh fungsi CRUD:
public function index() {
return Article::all();
}
public function store(Request $request) {
$validated = $request->validate([
'title' => 'required',
'content' => 'required',
]);
// Ownership: artikel milik user login
$article = $request->user()->articles()->create($validated);
return response()->json($article, 201);
}
public function show(Request $request, $id) {
$article = Article::findOrFail($id);
// Authorization: hanya pemilik yang boleh akses
if ($article->user_id !== $request->user()->id) {
abort(403, 'Unauthorized');
}
return $article;
}
public function update(Request $request, $id) {
$article = Article::findOrFail($id);
if ($article->user_id !== $request->user()->id) {
abort(403, 'Unauthorized');
}
$validated = $request->validate([
'title' => 'required',
'content' => 'required',
]);
$article->update($validated);
return response()->json($article);
}
public function destroy(Request $request, $id) {
$article = Article::findOrFail($id);
if ($article->user_id !== $request->user()->id) {
abort(403, 'Unauthorized');
}
$article->delete();
return response()->json(null, 204);
}
Step 5: Route API
Edit routes/api.php:
use App\Http\Controllers\Api\AuthController;
use App\Http\Controllers\Api\ArticleController;
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::apiResource('articles', ArticleController::class);
});
Step 6: Testing API CRUD dengan Postman
| Method | Endpoint | Fungsi |
|---|---|---|
| GET | /api/articles | List semua artikel |
| POST | /api/articles | Simpan artikel baru |
| GET | /api/articles/{id} | Detail artikel |
| PUT | /api/articles/{id} | Update artikel |
| DELETE | /api/articles/{id} | Hapus artikel |
Jangan lupa kirim token di header:
Authorization: Bearer {token}
Contoh Response JSON
{
"id": 1,
"title": "Belajar Laravel API",
"content": "Laravel API itu powerful...",
"user_id": 1,
"created_at": "2026-01-11"
}
Kenapa API Ini Aman?
Dengan Sanctum + auth:sanctum, API ini tidak bisa diakses tanpa token. Setiap request divalidasi berdasarkan user yang login, dan hanya pemilik data yang bisa mengakses/mengubah artikelnya sendiri.
Kalau Mau Dipakai di Frontend
- React: simpan token di localStorage, kirim di header Authorization setiap request
- Axios: gunakan interceptor untuk otomatis attach token
- Jangan expose token di public repo!
Error Handling & Status Code
- 201 Created: Data berhasil dibuat
- 200 OK: Data berhasil diambil/diupdate
- 204 No Content: Data dihapus
- 401 Unauthorized: Token salah/expired
- 404 Not Found: Data tidak ditemukan
- 422 Unprocessable Entity: Validasi gagal
Common Mistake Pemula
- Lupa migrate/publish Sanctum
- Lupa middleware
auth:sanctum - Token tidak dikirim di header
- Lupa set
Accept: application/json - Salah endpoint (POST login, bukan GET)
- Salah group route (harus di dalam middleware)
Next Step
- API Resource (response lebih rapi)
- Pagination & filtering
- Role & permission
- Testing dengan Thunder Client
🚀 Yuk Diskusi & Share!
Kalau kamu stuck di step tertentu, tulis di komentar ya! Share juga pengalaman kamu bikin API CRUD Laravel, atau request topik lanjutan (API Resource, pagination, dsb).
Referensi:
Top comments (0)