Membangun API Laravel yang Aman dengan Autentikasi JWT
Autentikasi JWT (JSON Web Token) di Laravel menyediakan mekanisme yang ditandatangani secara kriptografis dan stateless untuk memverifikasi konsumen API tanpa penyimpanan sesi di sisi server. JWT mengenkode payload — biasanya identitas pengguna dan klaim — ke dalam string yang ringkas dan aman untuk URL yang ditandatangani dengan kunci rahasia atau RSA, memungkinkan layanan mana pun yang memegang kunci verifikasi untuk memvalidasi token secara independen.
Panduan ini mencakup implementasi lengkap autentikasi JWT dalam API Laravel menggunakan paket `tymon/jwt-auth`, termasuk pengaturan, konfigurasi model, logika controller, perlindungan rute, strategi refresh token, dan penguatan untuk produksi. Setiap langkah mencakup konteks teknis yang melampaui tutorial tingkat permukaan.
Prasyarat dan Asumsi Lingkungan
Sebelum memulai, konfirmasikan hal-hal berikut:
- PHP 8.1 atau lebih tinggi (PHP 8.2 direkomendasikan untuk Laravel 11)
- Laravel 10 atau 11 yang diinstal melalui Composer
- Composer 2.x
- MySQL 8.0, PostgreSQL 15, atau database yang kompatibel dengan PDO
- File `.env` yang dikonfigurasi dengan kredensial `DB_*` yang valid
- Pemahaman dasar tentang service container, middleware, dan Eloquent ORM Laravel
Jika Anda mendeploy API ini ke lingkungan produksi, paket VPS Hosting dengan akses root penuh memberi Anda kendali yang diperlukan untuk mengonfigurasi PHP-FPM, mengelola variabel lingkungan dengan aman, dan mengatur izin file dengan benar — semuanya penting untuk manajemen rahasia JWT.
Langkah 1: Buat Proyek Laravel Baru
“`bash
composer create-project laravel/laravel laravel-jwt-api
cd laravel-jwt-api
“`
Verifikasi instalasi:
“`bash
php artisan –version
“`
Atur kunci aplikasi Anda jika tidak dibuat secara otomatis:
“`bash
php artisan key:generate
“`
`APP_KEY` di `.env` terpisah dari rahasia JWT. Keduanya diperlukan dan melayani tujuan kriptografis yang berbeda — `APP_KEY` melindungi cookie terenkripsi dan data sesi, sementara `JWT_SECRET` menandatangani token.
Langkah 2: Instal Paket Autentikasi JWT
Paket `tymon/jwt-auth` adalah standar de facto untuk JWT di Laravel. Instal dengan:
“`bash
composer require tymon/jwt-auth
“`
Publikasikan konfigurasi paket:
“`bash
php artisan vendor:publish –provider="TymonJWTAuthProvidersLaravelServiceProvider"
“`
Ini membuat `config/jwt.php`, yang mengontrol TTL token, TTL refresh, algoritma, perilaku blacklist, dan klaim yang diperlukan. Tinjau file ini dengan cermat — defaultnya masuk akal untuk pengembangan tetapi memerlukan penyesuaian untuk produksi.
Parameter konfigurasi utama di `config/jwt.php`:
| Parameter | Default | Rekomendasi Produksi |
|---|
| — | — | — |
|---|
| `ttl` | 60 menit | 15–30 menit |
|---|
| `refresh_ttl` | 20160 menit (2 minggu) | 1440–10080 menit |
|---|
| `algo` | `HS256` | `RS256` untuk sistem terdistribusi |
|---|
| `blacklist_enabled` | `true` | Harus `true` |
|---|
| `blacklist_grace_period` | 0 detik | 10–30 detik untuk permintaan bersamaan |
|---|
| `required_claims` | `['iss','iat','exp','nbf','sub','jti']` | Pertahankan semua; tambahkan `aud` untuk API multi-tenant |
|---|
Langkah 3: Buat Kunci Rahasia JWT
“`bash
php artisan jwt:secret
“`
Ini menambahkan `JWT_SECRET` ke file `.env` Anda. Nilai ini digunakan sebagai kunci penandatanganan HMAC-SHA256 untuk semua token saat menggunakan algoritma `HS256` default.
Catatan keamanan penting:
- Jangan pernah melakukan commit `.env` ke version control. Tambahkan ke `.gitignore` segera.
- Pada pipeline deployment bersama, masukkan `JWT_SECRET` sebagai variabel lingkungan melalui sistem CI/CD Anda daripada menyimpannya dalam file.
- Jika Anda merotasi rahasia, semua token yang ada langsung tidak valid. Rencanakan jendela rotasi dengan tepat dan komunikasikan kepada konsumen API.
- Untuk arsitektur layanan mikro di mana beberapa layanan harus memverifikasi token, beralih ke `RS256`. Buat pasangan kunci RSA, simpan kunci privat di layanan autentikasi, dan distribusikan hanya kunci publik ke layanan yang mengonsumsinya.
Langkah 4: Konfigurasi Guard Autentikasi
Buka `config/auth.php` dan perbarui bagian defaults dan guards:
“`php
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
“`
Ini menginstruksikan sistem autentikasi Laravel untuk menggunakan driver JWT saat menyelesaikan guard `api`. Middleware `auth:api` sekarang akan mendelegasikan validasi token ke `tymon/jwt-auth` alih-alih Laravel Passport atau driver token default.
Jangan hapus guard `web`. Banyak komponen internal Laravel bergantung padanya, dan menghapusnya menyebabkan kegagalan tak terduga dalam perintah konsol dan queue worker yang berinteraksi dengan sistem autentikasi.
Langkah 5: Buat Model User dan Migrasi
Jika model `User` dan migrasi default sudah ada (ada dalam instalasi Laravel baru), Anda dapat memodifikasinya langsung. Jika memulai dari awal:
“`bash
php artisan make:model User -m
“`
Buka file migrasi di `database/migrations/` dan definisikan skema:
“`php
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
“`
Jalankan migrasi:
“`bash
php artisan migrate
“`
Catatan produksi: Selalu jalankan migrasi dengan flag `–force` di lingkungan produksi di mana `APP_ENV=production`, karena Laravel akan meminta konfirmasi jika tidak:
“`bash
php artisan migrate –force
“`
Langkah 6: Implementasikan Interface JWTSubject di Model User
Paket `tymon/jwt-auth` mengharuskan model yang dapat diautentikasi Anda mengimplementasikan kontrak `JWTSubject`. Buka `app/Models/User.php`:
“`php
<?php
namespace AppModels;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateFoundationAuthUser as Authenticatable;
use IlluminateNotificationsNotifiable;
use TymonJWTAuthContractsJWTSubject;
class User extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
/**
- Get the identifier that will be stored in the JWT subject claim.
*/
public function getJWTIdentifier(): mixed
{
return $this->getKey();
}
/**
- Return a key-value array of arbitrary claims to add to the JWT payload.
*/
public function getJWTCustomClaims(): array
{
return [];
}
}
“`
Tentang klaim kustom: Metode `getJWTCustomClaims()` adalah tempat Anda menyematkan data spesifik aplikasi langsung ke dalam payload token. Kasus penggunaan umum meliputi penyematan `role`, `tenant_id`, atau `permissions` sehingga layanan hilir dapat membuat keputusan otorisasi tanpa pencarian database. Berhati-hatilah tentang apa yang Anda sematkan — setiap klaim meningkatkan ukuran token dan dapat dibaca oleh siapa saja yang mendekode base64 payload. Jangan pernah menyematkan data sensitif seperti kata sandi atau PII.
Langkah 7: Bangun Controller Autentikasi
“`bash
php artisan make:controller AuthController
“`
Isi `app/Http/Controllers/AuthController.php` dengan logika autentikasi lengkap:
“`php
<?php
namespace AppHttpControllers;
use AppModelsUser;
use IlluminateHttpJsonResponse;
use IlluminateHttpRequest;
use IlluminateSupportFacadesAuth;
use IlluminateSupportFacadesHash;
use IlluminateValidationValidationException;
use TymonJWTAuthExceptionsJWTException;
use TymonJWTAuthFacadesJWTAuth;
class AuthController extends Controller
{
/**
- Register a new user and return a JWT.
*/
public function register(Request $request): JsonResponse
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8|confirmed',
]);
$user = User::create([
'name' => $validated['name'],
'email' => $validated['email'],
'password' => Hash::make($validated['password']),
]);
$token = JWTAuth::fromUser($user);
return response()->json([
'token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60,
], 201);
}
/**
- Authenticate a user and return a JWT.
*/
public function login(Request $request): JsonResponse
{
$credentials = $request->validate([
'email' => 'required|string|email',
'password' => 'required|string',
]);
if (!$token = Auth::guard('api')->attempt($credentials)) {
return response()->json(['error' => 'Invalid credentials'], 401);
}
return $this->respondWithToken($token);
}
/**
- Invalidate the current token (logout).
*/
public function logout(): JsonResponse
{
try {
Auth::guard('api')->logout();
} catch (JWTException $e) {
return response()->json(['error' => 'Failed to invalidate token'], 500);
}
return response()->json(['message' => 'Successfully logged out']);
}
/**
- Refresh the current token.
*/
public function refresh(): JsonResponse
{
try {
$token = Auth::guard('api')->refresh();
} catch (JWTException $e) {
return response()->json(['error' => 'Token cannot be refreshed'], 401);
}
return $this->respondWithToken($token);
}
/**
- Return the authenticated user's profile.
*/
public function me(): JsonResponse
{
return response()->json(Auth::guard('api')->user());
}
/**
- Format the token response consistently.
*/
protected function respondWithToken(string $token): JsonResponse
{
return response()->json([
'token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60,
]);
}
}
“`
Mengapa spesifikasi guard eksplisit penting: Memanggil `Auth::attempt()` tanpa menentukan guard akan kembali ke guard default. Jika Anda telah mengubah default ke `api`, ini berfungsi — tetapi tidak stabil. Selalu panggil `Auth::guard('api')->attempt()` secara eksplisit untuk menghindari bug halus saat guard default berubah selama refactoring.
Langkah 8: Definisikan Rute API
Buka `routes/api.php` dan definisikan rute autentikasi dan yang dilindungi:
“`php
<?php
use AppHttpControllersAuthController;
use IlluminateSupportFacadesRoute;
// Public authentication routes
Route::prefix('auth')->group(function () {
Route::post('register', [AuthController::class, 'register']);
Route::post('login', [AuthController::class, 'login']);
});
// Protected routes — require a valid JWT
Route::middleware('auth:api')->prefix('auth')->group(function () {
Route::post('logout', [AuthController::class, 'logout']);
Route::post('refresh', [AuthController::class, 'refresh']);
Route::get('me', [AuthController::class, 'me']);
});
// Example protected resource routes
Route::middleware('auth:api')->group(function () {
Route::apiResource('posts', AppHttpControllersPostController::class);
});
“`
Strategi prefix rute: Mengelompokkan endpoint autentikasi di bawah `/api/auth/` adalah konvensi yang banyak diadopsi yang membuat dokumentasi API lebih bersih dan menyederhanakan aturan pembatasan laju — Anda dapat menerapkan throttling yang lebih ketat ke `/api/auth/login` secara independen dari endpoint resource.
Langkah 9: Melindungi Rute dan Menangani Kegagalan Middleware
Middleware `auth:api` Laravel akan mengembalikan respons `401 Unauthenticated` ketika token hilang, kedaluwarsa, atau tidak valid. Untuk mengembalikan respons JSON yang konsisten alih-alih pengalihan HTML, timpa metode `unauthenticated` di `app/Exceptions/Handler.php`:
“`php
use IlluminateAuthAuthenticationException;
use IlluminateHttpRequest;
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson() || $request->is('api/*')) {
return response()->json(['error' => 'Unauthenticated'], 401);
}
return redirect()->guest(route('login'));
}
“`
Tanpa penimpaan ini, klien API menerima pengalihan HTML 302 ke halaman login yang tidak ada dalam aplikasi API murni — sumber kebingungan umum selama pengujian integrasi.
Langkah 10: Strategi Refresh Token dan Blacklisting
Sifat stateless JWT menciptakan ketegangan: token bersifat mandiri dan valid hingga kedaluwarsa, tetapi Anda memerlukan cara untuk mencabutnya saat logout. Paket `tymon/jwt-auth` menyelesaikan ini dengan blacklist token yang didukung oleh driver cache Laravel.
Cara kerja blacklist:
- Saat logout, klaim `jti` (JWT ID) token disimpan dalam cache dengan TTL yang sesuai dengan sisa masa berlaku token.
- Pada setiap permintaan yang diautentikasi, middleware memeriksa blacklist sebelum menerima token.
- Pengaturan `blacklist_grace_period` memungkinkan jendela singkat di mana token yang sedang di-refresh masih dapat digunakan, mencegah kondisi balapan pada klien yang membuat permintaan bersamaan.
Pastikan driver cache Anda mendukung ini. Driver `file` default berfungsi untuk deployment server tunggal. Untuk API yang diskalakan secara horizontal yang berjalan di beberapa node — umum saat menggunakan Dedicated Server dalam konfigurasi load-balanced — beralih ke Redis atau Memcached:
“`env
CACHE_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
“`
Alur refresh token:
“`
Client API Server
| — POST /api/auth/refresh ——> |
|---|
| Authorization: Bearer <old> |
|---|
| — Validate old token |
|---|
| — Blacklist old token's jti |
|---|
| — Issue new token |
|---|
| <– 200 { token: <new> } ——– |
|---|
“`
Token lama langsung di-blacklist setelah refresh. Klien harus menyimpan token baru dan membuang yang lama. Implementasikan ini sebagai interceptor Axios atau yang setara di frontend Anda untuk menangani refresh token secara transparan.
Langkah 11: Menguji API
Gunakan `curl` atau Postman untuk memverifikasi setiap endpoint.
Daftarkan pengguna:
“`bash
curl -X POST https://your-domain.com/api/auth/register
-H "Content-Type: application/json"
-d '{
"name": "Jane Smith",
"email": "jane@example.com",
"password": "SecurePass123!",
"password_confirmation": "SecurePass123!"
}'
“`
Respons yang diharapkan (`201 Created`):
“`json
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…",
"token_type": "bearer",
"expires_in": 3600
}
“`
Masuk:
“`bash
curl -X POST https://your-domain.com/api/auth/login
-H "Content-Type: application/json"
-d '{"email": "jane@example.com", "password": "SecurePass123!"}'
“`
Akses rute yang dilindungi:
“`bash
curl -X GET https://your-domain.com/api/auth/me
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…"
“`
Refresh token:
“`bash
curl -X POST https://your-domain.com/api/auth/refresh
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…"
“`
Keluar:
“`bash
curl -X POST https://your-domain.com/api/auth/logout
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…"
“`
JWT vs. Sesi vs. Laravel Sanctum vs. Passport
Memahami kapan JWT adalah pilihan yang tepat memerlukan perbandingan dengan alternatif yang tersedia dalam ekosistem Laravel.
| Kriteria | JWT (`tymon/jwt-auth`) | Laravel Sanctum | Laravel Passport | Berbasis Sesi |
|---|
| — | — | — | — | — |
|---|
| **Statefulness** | Stateless | Stateless (token SPA) / Stateful (cookie) | Stateful (token DB) | Stateful |
|---|
| **Penyimpanan token** | Sisi klien | Sisi klien atau cookie | Database | Sesi sisi server |
|---|
| **Pencabutan** | Blacklist (cache) | Langsung (hapus DB) | Langsung (hapus DB) | Langsung |
|---|
| **Skalabilitas** | Sangat baik (tidak ada DB per permintaan) | Baik | Sedang (pencarian DB per permintaan) | Buruk (sinkronisasi sesi diperlukan) |
|---|
| **Dukungan OAuth2** | Tidak | Tidak | Ya (server OAuth2 penuh) | Tidak |
|---|
| **Kompleksitas** | Sedang | Rendah | Tinggi | Rendah |
|---|
| **Terbaik untuk** | API stateless, layanan mikro | SPA, aplikasi mobile | Klien OAuth pihak ketiga | Aplikasi web tradisional |
|---|
| **Introspeksi token** | Dekode payload sisi klien | Memerlukan panggilan API | Memerlukan panggilan API | N/A |
|---|
Kapan memilih JWT daripada Sanctum: Jika API Anda dikonsumsi oleh klien pihak ketiga, aplikasi mobile, atau layanan mikro yang tidak dapat berbagi cookie sesi atau koneksi database dengan aplikasi Laravel Anda, sifat mandiri JWT adalah keunggulan yang signifikan. Jika Anda membangun SPA first-party di domain yang sama, Sanctum dengan autentikasi berbasis cookie lebih sederhana dan sepenuhnya menghindari masalah keamanan penyimpanan token.
Penguatan Keamanan Produksi
Implementasi JWT yang berfungsi tidak secara default aman. Terapkan langkah-langkah penguatan ini sebelum go live:
1. Terapkan HTTPS tanpa syarat
Token JWT yang ditransmisikan melalui HTTP dapat dengan mudah disadap. Terapkan TLS di tingkat web server dan alihkan semua lalu lintas HTTP. Padukan ini dengan Sertifikat SSL untuk memastikan transport terenkripsi untuk setiap permintaan API.
2. Tetapkan TTL token yang agresif
Token akses berumur pendek (15–30 menit) dikombinasikan dengan token refresh berumur lebih panjang (7–14 hari) membatasi dampak token yang dicuri. Perbarui `config/jwt.php`:
“`php
'ttl' => 15,
'refresh_ttl' => 10080,
“`
3. Terapkan pembatasan laju pada endpoint autentikasi
Middleware throttle bawaan Laravel mencegah serangan brute-force:
“`php
Route::middleware(['throttle:10,1'])->group(function () {
Route::post('auth/login', [AuthController::class, 'login']);
Route::post('auth/register', [AuthController::class, 'register']);
});
“`
Ini membatasi setiap IP hingga 10 permintaan per menit pada endpoint autentikasi.
4. Validasi klaim `aud` untuk API multi-tenant
Jika API Anda melayani beberapa aplikasi klien, sematkan dan validasi klaim `audience` untuk mencegah penggunaan ulang token lintas layanan:
“`php
// In getJWTCustomClaims()
return [
'aud' => config('app.jwt_audience'),
];
“`
5. Lindungi JWT_SECRET di tingkat OS
Tetapkan izin file yang ketat pada `.env`:
“`bash
chmod 640 .env
chown www-data:www-data .env
“`
Pada VPS dengan cPanel yang dikonfigurasi dengan benar, Anda dapat mengelola kepemilikan dan izin file melalui File Manager atau SSH tanpa risiko mengekspos rahasia kepada pengguna lain di sistem.
6. Catat peristiwa autentikasi
Integrasikan sistem event Laravel untuk mencatat percobaan login yang gagal, refresh token, dan logout ke layanan logging terpusat. Ini penting untuk deteksi anomali.
Menambahkan Kontrol Akses Berbasis Peran
Klaim kustom memudahkan penyematan peran langsung dalam token:
“`php
// In User model
public function getJWTCustomClaims(): array
{
return [
'role' => $this->role, // e.g., 'admin', 'editor', 'viewer'
];
}
“`
Buat middleware untuk menegakkan persyaratan peran:
“`php
<?php
namespace AppHttpMiddleware;
use Closure;
use IlluminateHttpRequest;
use TymonJWTAuthFacadesJWTAuth;
class RoleMiddleware
{
public function handle(Request $request, Closure $next, string $role): mixed
{
$payload = JWTAuth::parseToken()->getPayload();
if ($payload->get('role') !== $role) {
return response()->json(['error' => 'Forbidden'], 403);
}
return $next($request);
}
}
“`
Daftarkan di `app/Http/Kernel.php` (Laravel 10) atau `bootstrap/app.php` (Laravel 11) dan terapkan ke rute:
“`php
Route::middleware(['auth:api', 'role:admin'])->group(function () {
Route::apiResource('admin/users', AdminUserController::class);
});
“`
Peringatan: Data peran yang disematkan dalam token hanya seakurat token itu sendiri. Jika peran pengguna berubah, token lama terus memberikan peran lama hingga kedaluwarsa atau di-refresh. Untuk perubahan peran dengan keamanan tinggi (misalnya, mencabut akses admin segera), kombinasikan blacklisting token dengan TTL pendek atau lakukan pemeriksaan peran database di middleware bersamaan dengan pemeriksaan klaim.
Pertimbangan Deployment untuk API JWT Laravel
Saat berpindah dari pengembangan lokal ke server produksi, beberapa faktor spesifik lingkungan memengaruhi perilaku JWT:
- Konsistensi zona waktu: Klaim `iat`, `nbf`, dan `exp` JWT adalah timestamp Unix. Pastikan zona waktu server Anda diatur ke UTC (`date.timezone = UTC` di `php.ini`) untuk mencegah penolakan token akibat perbedaan jam.
- OPcache: Aktifkan PHP OPcache untuk mengurangi overhead pemuatan file library JWT pada setiap permintaan. Ini sangat berdampak pada API dengan lalu lintas tinggi.
- Queue worker untuk pembersihan token: Jika Anda mengimplementasikan job pembersihan blacklist token kustom, pastikan queue worker Anda berjalan sebagai proses yang diawasi (Supervisor atau systemd).
- Manajemen variabel lingkungan: Pada Panel Kontrol VPS, gunakan manajer variabel lingkungan panel daripada mengedit `.env` langsung di produksi, untuk menghindari penimpaan yang tidak disengaja selama deployment.
Daftar Periksa Keputusan Sebelum Go Live
Gunakan daftar periksa ini untuk memverifikasi implementasi Anda siap untuk produksi:
- `JWT_SECRET` minimal 32 karakter, dibuat secara acak, dan tidak di-commit ke version control
- `blacklist_enabled` diatur ke `true` di `config/jwt.php`
- TTL token adalah 30 menit atau kurang untuk token akses
- TTL refresh diatur ke nilai yang sesuai dengan kebijakan sesi Anda
- Semua endpoint API disajikan secara eksklusif melalui HTTPS
- Pembatasan laju diterapkan pada endpoint `/login` dan `/register`
- Handler pengecualian `unauthenticated` mengembalikan JSON, bukan pengalihan HTML
- Klaim kustom tidak mengandung kata sandi, rahasia, atau PII sensitif
- Driver cache adalah Redis atau Memcached (bukan `file`) dalam deployment multi-server
- Peristiwa autentikasi dicatat dan dipantau
- Perubahan peran yang memerlukan efek segera ditangani melalui blacklisting, bukan hanya kedaluwarsa klaim
- Izin file `.env` dibatasi untuk pengguna web server
FAQ
Apa perbedaan antara `JWT_SECRET` dan `APP_KEY` di Laravel?
`APP_KEY` digunakan oleh layanan enkripsi Laravel untuk mengenkripsi cookie, data sesi, dan nilai yang diteruskan melalui `Crypt::encrypt()`. `JWT_SECRET` digunakan secara eksklusif oleh `tymon/jwt-auth` untuk menandatangani dan memverifikasi JSON Web Token. Keduanya secara kriptografis independen dan melayani tujuan yang sepenuhnya berbeda. Keduanya harus dijaga kerahasiaannya.
Mengapa token JWT saya terus mengembalikan 401 meskipun belum kedaluwarsa?
Penyebab paling umum adalah: token telah di-blacklist (misalnya, setelah logout atau refresh), `JWT_SECRET` dirotasi setelah token diterbitkan, driver cache yang menyimpan blacklist tidak tersedia, atau ada perbedaan jam antara server penerbit dan server validasi yang melebihi pengaturan `leeway` di `config/jwt.php`. Periksa masing-masing secara berurutan.
Bisakah saya menggunakan autentikasi JWT dengan queue atau perintah konsol Laravel?
JWT dirancang untuk autentikasi permintaan HTTP. Di dalam job queue atau perintah Artisan, tidak ada konteks permintaan HTTP, sehingga Anda tidak dapat menyelesaikan pengguna dari token melalui middleware. Sebagai gantinya, teruskan kunci primer pengguna sebagai parameter job dan muat model secara langsung dengan `User::find($userId)`.
Bagaimana cara menangani permintaan bersamaan selama refresh token tanpa mendapatkan error 401?
Atur `blacklist_grace_period` di `config/jwt.php` ke nilai antara 10 dan 30 detik. Selama jendela ini, token yang baru saja di-refresh (dan secara teknis di-blacklist) masih akan diterima. Ini mencegah kondisi balapan pada klien yang mengirim beberapa permintaan simultan saat refresh sedang berlangsung.
Apakah `tymon/jwt-auth` kompatibel dengan Laravel 11?
Pada siklus rilis saat ini, `tymon/jwt-auth` versi `2.x` mendukung Laravel 10 dan 11 melalui cabang `dev-develop` atau rilis bertag yang menyatakan kompatibilitas. Selalu periksa batasan `composer.json` paket dan pelacak masalah GitHub sebelum meningkatkan versi Laravel dalam proyek yang bergantung pada paket ini. Pertimbangkan untuk menyematkan versi paket di `composer.json` untuk menghindari perubahan yang merusak secara tak terduga selama `composer update`.
