Authentication API (Sanctum) dan Proteksi Endpoint - Perwira Learning Center

 

1. LATAR BELAKANG

    Setelah membangun API yang robust dengan validasi, error handling, dan response yang konsisten, tiba saatnya untuk membahas aspek paling kritis dalam pengembangan API: keamanan dan autentikasi. API yang kita bangun sejauh ini bersifat publik—siapa pun bisa mengakses, membuat, mengupdate, atau menghapus data. Tentunya ini tidak aman untuk aplikasi production.

Pada hari kelima minggu ini, saya mempelajari bagaimana mengamankan API menggunakan Laravel Sanctum. Sanctum adalah paket autentikasi ringan untuk API yang memungkinkan kita mengeluarkan token API kepada pengguna. Setiap request ke endpoint yang dilindungi harus menyertakan token ini untuk membuktikan identitas pengguna.

Mengapa Sanctum? Karena:

  • Sederhana - Mudah diintegrasikan
  • Ringan - Tidak membawa banyak fitur yang tidak diperlukan
  • Fleksibel - Bisa untuk API token maupun autentikasi SPA
  • First-party - Dikembangkan langsung oleh tim Laravel

Dengan Sanctum, kita bisa membedakan akses antara pengguna biasa, admin, atau bahkan tamu (guest), serta melindungi endpoint tertentu agar hanya bisa diakses oleh pengguna yang memiliki hak akses yang sesuai.


2. ALAT DAN BAHAN

2.1 Perangkat Lunak

  • Laravel 11 - Project API yang sudah berjalan (dari artikel sebelumnya)
  • Laravel Sanctum - Paket autentikasi API (akan diinstall)
  • Postman/Thunder Client - Untuk testing endpoint dengan token
  • Visual Studio Code - Editor kode
  • Git Bash/Terminal - Untuk menjalankan perintah Artisan

2.2 Perangkat Keras

  • Laptop dengan spesifikasi standar
  • Koneksi internet (untuk instalasi paket)

3. PEMBAHASAN

3.1 Apa itu Laravel Sanctum?

Laravel Sanctum adalah paket autentikasi yang dirancang khusus untuk API. Sanctum bekerja dengan cara mengeluarkan API token kepada pengguna yang berhasil login. Token ini kemudian harus disertakan dalam setiap request ke endpoint yang dilindungi, biasanya melalui header Authorization: Bearer {token}.

Cara Kerja Sanctum:

  1. Pengguna mengirim email dan password ke endpoint login
  2. Sistem memverifikasi kredensial
  3. Jika valid, sistem membuat token unik dan mengembalikannya ke pengguna
  4. Pengguna menyimpan token ini (di mobile app/local storage)
  5. Setiap request berikutnya, pengguna menyertakan token di header
  6. Sistem memverifikasi token sebelum memproses request

3.2 Instalasi dan Konfigurasi Sanctum

3.2.1 Install Paket Sanctum
bash
# Install sanctum via composer
composer require laravel/sanctum

# Publish migration dan konfigurasi
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

# Jalankan migration untuk membuat tabel personal_access_tokens
php artisan migrate
3.2.2 Konfigurasi Model User

Tambahkan trait HasApiTokens ke model User:

php
<?php
// File: app/Models/User.php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens; // Tambahkan ini

class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable; // Tambahkan HasApiTokens

/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];

/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];

/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
/**
* Relasi ke posts
*/
public function posts()
{
return $this->hasMany(Post::class);
}
}
3.2.3 Konfigurasi Middleware di Kernel

Pastikan middleware auth:sanctum sudah terdaftar. Biasanya sudah otomatis, tapi bisa dicek di app/Http/Kernel.php:

php
// File: app/Http/Kernel.php

protected $routeMiddleware = [
// ...
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
// ...
];
3.2.4 Konfigurasi di routes/api.php
php
<?php
// File: routes/api.php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\AuthController;
use App\Http\Controllers\Api\PostController;
use App\Http\Controllers\Api\UserController;

// ===== PUBLIC ROUTES (Tidak perlu token) =====
Route::prefix('auth')->group(function () {
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
});

// Posts yang bisa diakses publik (hanya baca)
Route::get('/posts', [PostController::class, 'index']);
Route::get('/posts/{post}', [PostController::class, 'show']);

// ===== PROTECTED ROUTES (Perlu token) =====
Route::middleware('auth:sanctum')->group(function () {
// User profile
Route::get('/user', [AuthController::class, 'user']);
Route::post('/logout', [AuthController::class, 'logout']);
// CRUD Posts (kecuali index dan show sudah publik)
Route::apiResource('posts', PostController::class)->except(['index', 'show']);
// Manajemen token
Route::get('/tokens', [AuthController::class, 'tokens']);
Route::delete('/tokens/{token}', [AuthController::class, 'revokeToken']);
});

3.3 Membuat Controller Autentikasi

3.3.1 AuthController
bash
php artisan make:controller Api/AuthController
php
<?php
// File: app/Http/Controllers/Api/AuthController.php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\LoginRequest;
use App\Http\Requests\RegisterRequest;
use App\Models\User;
use App\Traits\ApiResponseTrait;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
use ApiResponseTrait;
/**
* Register user baru
* POST /api/auth/register
*/
public function register(RegisterRequest $request)
{
// Data sudah tervalidasi dari Form Request
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
'role' => 'user' // Default role
]);
// Buat token untuk user yang baru register (otomatis login)
$token = $user->createToken('auth_token')->plainTextToken;
return $this->successResponse([
'user' => [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'role' => $user->role,
'created_at' => $user->created_at->format('d M Y')
],
'token' => $token,
'token_type' => 'Bearer'
], 'Registrasi berhasil', 201);
}
/**
* Login user
* POST /api/auth/login
*/
public function login(LoginRequest $request)
{
$request->authenticate(); // Method dari Form Request
$user = $request->user();
// Hapus token lama jika ingin hanya 1 token aktif
// $user->tokens()->delete();
// Buat token baru
$token = $user->createToken('auth_token')->plainTextToken;
// Simpan log login (opsional)
activity()->log('User login');
return $this->successResponse([
'user' => [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'role' => $user->role,
'email_verified' => !is_null($user->email_verified_at)
],
'token' => $token,
'token_type' => 'Bearer',
'expires_in' => config('sanctum.expiration') // jika diatur
], 'Login berhasil');
}
/**
* Logout user (hapus token yang digunakan)
* POST /api/auth/logout
*/
public function logout(Request $request)
{
// Hapus token yang sedang digunakan
$request->user()->currentAccessToken()->delete();
// Atau hapus semua token user
// $request->user()->tokens()->delete();
return $this->successResponse(null, 'Logout berhasil');
}
/**
* Get authenticated user
* GET /api/user
*/
public function user(Request $request)
{
$user = $request->user()->load(['posts' => function($query) {
$query->latest()->limit(5);
}]);
return $this->successResponse([
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'role' => $user->role,
'avatar' => $user->avatar ? url($user->avatar) : null,
'joined_at' => $user->created_at->diffForHumans(),
'stats' => [
'total_posts' => $user->posts()->count(),
'total_comments' => $user->comments()->count(),
'total_likes' => $user->likes()->count()
],
'recent_posts' => $user->posts->map(function($post) {
return [
'id' => $post->id,
'title' => $post->title,
'slug' => $post->slug,
'created_at' => $post->created_at->format('d M Y')
];
})
], 'Data user berhasil diambil');
}
/**
* Dapatkan daftar token user
* GET /api/tokens
*/
public function tokens(Request $request)
{
$tokens = $request->user()->tokens()->get()->map(function($token) {
return [
'id' => $token->id,
'name' => $token->name,
'abilities' => $token->abilities,
'last_used_at' => $token->last_used_at ? $token->last_used_at->diffForHumans() : null,
'created_at' => $token->created_at->format('d M Y H:i')
];
});
return $this->successResponse($tokens, 'Daftar token berhasil diambil');
}
/**
* Revoke (cabut) token tertentu
* DELETE /api/tokens/{token}
*/
public function revokeToken($tokenId)
{
$user = request()->user();
// Cari token milik user ini
$token = $user->tokens()->where('id', $tokenId)->first();
if (!$token) {
return $this->notFoundResponse('Token tidak ditemukan');
}
// Hapus token
$token->delete();
return $this->successResponse(null, 'Token berhasil dicabut');
}
/**
* Ganti password
* POST /api/change-password
*/
public function changePassword(Request $request)
{
$request->validate([
'current_password' => 'required|current_password',
'new_password' => 'required|min:8|confirmed'
]);
$user = $request->user();
$user->password = Hash::make($request->new_password);
$user->save();
// Opsional: logout dari semua device
// $user->tokens()->delete();
return $this->successResponse(null, 'Password berhasil diubah');
}
}
3.3.2 Form Request untuk Autentikasi
bash
php artisan make:request RegisterRequest
php artisan make:request LoginRequest

RegisterRequest:

php
<?php
// File: app/Http/Requests/RegisterRequest.php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;

class RegisterRequest extends FormRequest
{
public function authorize(): bool
{
return true; // Semua orang boleh register
}

public function rules(): array
{
return [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8|confirmed',
'password_confirmation' => 'required|string|min:8',
'terms' => 'accepted' // Setuju syarat & ketentuan
];
}

public function messages(): array
{
return [
'name.required' => 'Nama lengkap wajib diisi',
'email.required' => 'Email wajib diisi',
'email.email' => 'Format email tidak valid',
'email.unique' => 'Email sudah terdaftar',
'password.required' => 'Password wajib diisi',
'password.min' => 'Password minimal 8 karakter',
'password.confirmed' => 'Konfirmasi password tidak cocok',
'terms.accepted' => 'Anda harus menyetujui syarat dan ketentuan'
];
}

protected function failedValidation(Validator $validator)
{
throw new HttpResponseException(
response()->json([
'success' => false,
'message' => 'Validasi gagal',
'errors' => $validator->errors()
], 422)
);
}
}

LoginRequest:

php
<?php
// File: app/Http/Requests/LoginRequest.php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;

class LoginRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}

public function rules(): array
{
return [
'email' => 'required|string|email',
'password' => 'required|string',
'device_name' => 'nullable|string|max:255' // Untuk memberi nama token
];
}

public function messages(): array
{
return [
'email.required' => 'Email wajib diisi',
'email.email' => 'Format email tidak valid',
'password.required' => 'Password wajib diisi'
];
}

/**
* Attempt to authenticate the request's credentials.
*
* @throws \Illuminate\Validation\ValidationException
*/
public function authenticate(): void
{
if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
throw ValidationException::withMessages([
'email' => ['Email atau password salah.'],
]);
}
}
}

3.4 Proteksi Endpoint dengan Middleware

3.4.1 Middleware auth:sanctum

Middleware auth:sanctum akan memeriksa apakah request menyertakan token yang valid. Jika tidak, akan mengembalikan response 401 Unauthorized.

php
// Di routes/api.php
Route::middleware('auth:sanctum')->group(function () {
// Semua route di sini dilindungi
Route::apiResource('posts', PostController::class)->except(['index', 'show']);
});
3.4.2 Membuat Middleware Kustom untuk Role
bash
php artisan make:middleware CheckRole
php
<?php
// File: app/Http/Middleware/CheckRole.php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class CheckRole
{
/**
* Handle an incoming request.
*/
public function handle(Request $request, Closure $next, ...$roles): Response
{
$user = $request->user();
if (!$user) {
return response()->json([
'success' => false,
'message' => 'Unauthenticated'
], 401);
}
// Cek apakah user memiliki role yang diizinkan
if (!in_array($user->role, $roles)) {
return response()->json([
'success' => false,
'message' => 'Anda tidak memiliki akses ke resource ini'
], 403);
}
return $next($request);
}
}

Daftarkan middleware di Kernel:

php
// File: app/Http/Kernel.php

protected $routeMiddleware = [
// ...
'role' => \App\Http\Middleware\CheckRole::class,
];

Penggunaan di routes:

php
Route::middleware(['auth:sanctum', 'role:admin'])->group(function () {
Route::apiResource('users', UserController::class);
Route::get('/dashboard/stats', [DashboardController::class, 'stats']);
});

Route::middleware(['auth:sanctum', 'role:admin,editor'])->group(function () {
Route::post('/posts/{post}/publish', [PostController::class, 'publish']);
});

3.5 Policy untuk Otorisasi (Authorization)

Policy memungkinkan kita mengatur logika otorisasi secara terpusat, misalnya hanya pemilik post yang boleh mengupdate atau menghapus post-nya.

3.5.1 Membuat Policy
bash
php artisan make:policy PostPolicy --model=Post
php
<?php
// File: app/Policies/PostPolicy.php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
use HandlesAuthorization;

/**
* Admin bisa melakukan apa saja
*/
public function before(User $user, $ability)
{
if ($user->role === 'admin') {
return true;
}
}

/**
* Determine whether the user can update the post.
*/
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}

/**
* Determine whether the user can delete the post.
*/
public function delete(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
/**
* Determine whether the user can publish the post.
*/
public function publish(User $user, Post $post): bool
{
return $user->id === $post->user_id || $user->role === 'editor';
}
}
3.5.2 Mendaftarkan Policy
php
// File: app/Providers/AuthServiceProvider.php

use App\Models\Post;
use App\Policies\PostPolicy;

class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
Post::class => PostPolicy::class,
];

// ...
}
3.5.3 Menggunakan Policy di Controller
php
<?php
// File: app/Http/Controllers/Api/PostController.php

use App\Models\Post;
use App\Http\Requests\UpdatePostRequest;

class PostController extends Controller
{
public function update(UpdatePostRequest $request, Post $post)
{
// Menggunakan Policy
$this->authorize('update', $post);
$validated = $request->validated();
$post->update($validated);
return $this->successResponse(
new PostResource($post),
'Post berhasil diupdate'
);
}
public function destroy(Post $post)
{
// Menggunakan Policy
$this->authorize('delete', $post);
$post->delete();
return $this->deletedResponse('Post berhasil dihapus');
}
public function publish(Post $post)
{
// Method kustom di policy
$this->authorize('publish', $post);
$post->update([
'is_published' => true,
'published_at' => now()
]);
return $this->successResponse(
new PostResource($post),
'Post berhasil dipublikasikan'
);
}
}

3.6 Membuat Resource untuk User

php
<?php
// File: app/Http/Resources/UserResource.php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'username' => $this->username ?? $this->email,
'email' => $this->email,
'role' => $this->role,
'avatar' => $this->avatar ? url($this->avatar) : null,
'bio' => $this->bio,
'joined_at' => $this->created_at->format('d M Y'),
'joined_ago' => $this->created_at->diffForHumans(),
'is_verified' => !is_null($this->email_verified_at),
'stats' => [
'posts_count' => $this->whenCounted('posts'),
'comments_count' => $this->whenCounted('comments'),
'likes_received' => $this->whenCounted('likesReceived')
]
];
}
}

3.7 Testing Endpoint dengan Postman

3.7.1 Register User

Request:

text
POST /api/auth/register
Content-Type: application/json

{ "name": "John Doe", "email": "john@example.com", "password": "password123", "password_confirmation": "password123", "terms": true
}

Response (201):

json
{
"success": true,
"message": "Registrasi berhasil",
"data": {
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"role": "user",
"created_at": "24 Feb 2026"
},
"token": "1|a1b2c3d4e5f6g7h8i9j0...",
"token_type": "Bearer"
}
}
3.7.2 Login User

Request:

text
POST /api/auth/login
Content-Type: application/json

{ "email": "john@example.com", "password": "password123"
}

Response (200):

json
{
"success": true,
"message": "Login berhasil",
"data": {
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"role": "user",
"email_verified": false
},
"token": "2|k1l2m3n4o5p6q7r8s9t0...",
"token_type": "Bearer"
}
}
3.7.3 Akses Protected Endpoint (dengan token)

Request:

text
POST /api/posts
Authorization: Bearer 2|k1l2m3n4o5p6q7r8s9t0...
Content-Type: application/json

{ "title": "Post dengan Auth", "content": "Ini adalah post yang dibuat setelah login", "category_id": 1
}

Response (201):

json
{
"success": true,
"message": "Post berhasil dibuat",
"data": {
"id": 5,
"title": "Post dengan Auth",
"content": "Ini adalah post yang dibuat setelah login",
"user_id": 1,
"created_at": "2 minutes ago"
}
}
3.7.4 Akses Tanpa Token (401)

Request:

text
POST /api/posts
Content-Type: application/json

{ "title": "Post tanpa Auth"
}

Response (401):

json
{
"message": "Unauthenticated."
}
3.7.5 Akses dengan Token Invalid (401)

Request:

text
POST /api/posts
Authorization: Bearer token_salah_123
Content-Type: application/json

Response (401):

json
{
"message": "Unauthenticated."
}
3.7.6 Akses dengan Role Tidak Sesuai (403)

Request:

text
DELETE /api/users/2 (Endpoint khusus admin)
Authorization: Bearer valid_token_user_biasa

Response (403):

json
{
"success": false,
"message": "Anda tidak memiliki akses ke resource ini"
}
3.7.7 Logout

Request:

text
POST /api/auth/logout
Authorization: Bearer 2|k1l2m3n4o5p6q7r8s9t0...

Response (200):

json
{
"success": true,
"message": "Logout berhasil",
"data": null
}

Token yang digunakan sekarang tidak valid lagi.

3.8 Fitur Lanjutan Sanctum

3.8.1 Token Abilities (Scopes)

Sanctum memungkinkan kita memberi "kemampuan" spesifik pada token:

php
// Membuat token dengan abilities terbatas
$token = $user->createToken('mobile-token', ['posts:read', 'profile:read'])->plainTextToken;

// Cek abilities di middleware/controller
if ($user->tokenCan('posts:create')) {
// Boleh membuat post
}

Penggunaan di routes:

php
Route::middleware(['auth:sanctum', 'abilities:posts:create'])->group(function () {
Route::post('/posts', [PostController::class, 'store']);
});

Route::middleware(['auth:sanctum', 'ability:posts:read,profile:read'])->group(function () {
Route::get('/posts', [PostController::class, 'index']);
Route::get('/user', [AuthController::class, 'user']);
});
3.8.2 Multiple Token per User

Satu user bisa memiliki banyak token untuk device yang berbeda:

php
// Login dari mobile
$mobileToken = $user->createToken('mobile-app')->plainTextToken;

// Login dari web
$webToken = $user->createToken('web-session')->plainTextToken;

// Login dari API third-party
$apiToken = $user->createToken('api-integration', ['posts:read'])->plainTextToken;
3.8.3 Token Expiration

Atur masa berlaku token di config/sanctum.php:

php
// config/sanctum.php
'expiration' => 60 * 24, // Token berlaku 24 jam (dalam menit)

Atau secara manual saat membuat token:

php
use Laravel\Sanctum\NewAccessToken;

$token = $user->createToken(
'auth_token',
['*'],
now()->addHours(24) // Expire dalam 24 jam
);

3.9 Menambahkan Fitur "Remember Me"

Modifikasi method login untuk mendukung remember token:

php
public function login(LoginRequest $request)
{
$credentials = $request->only('email', 'password');
$remember = $request->boolean('remember');
if (!Auth::attempt($credentials, $remember)) {
return $this->errorResponse('Email atau password salah', 401);
}
$user = Auth::user();
// Jika remember=true, buat token dengan masa berlaku lebih panjang
$expiration = $remember ? now()->addDays(30) : now()->addDays(1);
$token = $user->createToken(
$request->device_name ?? 'auth_token',
['*'],
$expiration
)->plainTextToken;
return $this->successResponse([
'user' => new UserResource($user),
'token' => $token,
'token_type' => 'Bearer',
'expires_at' => $expiration->format('Y-m-d H:i:s')
], 'Login berhasil');
}

3.10 Kendala dan Solusi

Kendala yang Dihadapi:

  1. Lupa menambahkan trait HasApiTokens di User model
    • Solusi: Selalu cek model User setelah install sanctum
  2. Token tidak dikirim dengan benar di header

    • Solusi: Pastikan format header Authorization: Bearer {token} (ada spasi setelah Bearer)
  3. Bingung membedakan autentikasi vs otorisasi

    • Autentikasi = siapa kamu? (login/logout) → auth:sanctum
    • Otorisasi = apa yang boleh kamu lakukan? → Policy & Role
  4. Token bocor atau perlu di-revoke

    • Solusi: Sediakan endpoint untuk melihat dan mencabut token
  5. User bisa akses data orang lain

    • Solusi: Gunakan Policy untuk memeriksa kepemilikan data


4. KESIMPULAN

Laravel Sanctum memberikan solusi autentikasi yang lengkap namun tetap sederhana untuk API kita. Dengan Sanctum, kita bisa:

  1. Mengelola Registrasi dan Login
    • User bisa mendaftar dan login dengan aman
    • Password di-hash menggunakan Bcrypt
  2. Membuat dan Mengelola Token

    • Setiap login menghasilkan token unik
    • Token bisa memiliki abilities (scope)
    • Token bisa di-revoke (logout)
  3. Melindungi Endpoint

    • Middleware auth:sanctum untuk endpoint yang perlu autentikasi
    • Response 401 untuk request tanpa token
    • Response 403 untuk akses tidak sah
  4. Otorisasi Berbasis Role dan Policy

    • Middleware role untuk membedakan akses admin/user
    • Policy untuk aturan spesifik (hanya pemilik yang boleh edit)

Dengan semua komponen ini, API kita sekarang:

  • Aman - Hanya user terautentikasi yang bisa mengakses endpoint tertentu
  • Terotorisasi - User hanya bisa mengakses data miliknya sendiri
  • Auditable - Bisa melacak token siapa yang mengakses apa
  • Profesional - Siap digunakan untuk aplikasi production

Pada artikel tambahan selanjutnya, kita akan mempelajari cara mendeploy REST API Laravel ke Laravel Cloud agar bisa diakses secara publik.


5. DAFTAR PUSTAKA

Posting Komentar

0 Komentar