Pencarian dan Autentikasi React + Laravel Sanctum (Part 4)

⚛️ Seri Fullstack React + Laravel — Manajemen Produk

  1. Part 1: Backend — REST API Laravel
  2. Part 2: Setup React & Tampil Data
  3. Part 3: CRUD React ↔ API
  4. Part 4: Pencarian & Autentikasi Sanctum (sedang dibaca)

Selamat datang di bagian terakhir seri fullstack React + Laravel. Dari Part 1 hingga Part 3, kita membangun aplikasi manajemen produk lengkap dengan API dan CRUD. Di Part 4 ini kita tambahkan pencarian, filter, dan yang terpenting: autentikasi token dengan Laravel Sanctum agar API tidak bisa diakses sembarangan.

Alur Autentikasi Token
Alur Autentikasi Token

Menambahkan Pencarian di React

Kita lakukan pencarian di sisi server (API) agar tetap efisien untuk data besar. Di backend, perbarui metode index() pada ProdukController agar menerima parameter pencarian:

public function index(Request $request)
{
    $produk = Produk::query()
        ->when($request->cari, function ($query, $cari) {
            $query->where('nama', 'like', "%{$cari}%");
        })
        ->when($request->kategori, function ($query, $kategori) {
            $query->where('kategori', $kategori);
        })
        ->latest()
        ->get();

    return ProdukResource::collection($produk);
}

Di frontend React, buat input pencarian yang memanggil API setiap kali kata kunci berubah:

import { useState, useEffect } from 'react';
import api from './api';

function App() {
  const [produk, setProduk] = useState([]);
  const [cari, setCari] = useState('');

  useEffect(() => {
    api.get('/produk', { params: { cari } })
      .then((res) => setProduk(res.data.data));
  }, [cari]);

  return (
    <div className="container">
      <h1>Manajemen Produk</h1>

      <input
        type="text"
        value={cari}
        onChange={(e) => setCari(e.target.value)}
        placeholder="Cari nama produk..."
      />

      {/* tabel produk seperti Part 3 */}
    </div>
  );
}

Perhatikan useEffect(() => {...}, [cari]) — dengan menaruh cari di array dependensi, React otomatis memanggil ulang API setiap kali kata kunci berubah. Inilah “keajaiban” reaktivitas React: ketik di kotak pencarian, hasil langsung diperbarui.

Pencarian produk real-time di React
Pencarian produk real-time di React

Memasang Laravel Sanctum

Sanctum adalah paket resmi Laravel untuk autentikasi API berbasis token. Pasang di proyek backend:

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

Pastikan model app/Models/User.php memakai trait HasApiTokens:

<?php

namespace App\Models;

use Laravel\Sanctum\HasApiTokens;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;

    // ...
}

Membuat Endpoint Login

Buat controller autentikasi yang mengembalikan token saat login berhasil:

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class AuthController extends Controller
{
    public function login(Request $request)
    {
        $request->validate([
            'email'    => 'required|email',
            'password' => 'required',
        ]);

        $user = User::where('email', $request->email)->first();

        if (! $user || ! Hash::check($request->password, $user->password)) {
            return response()->json(['pesan' => 'Email atau password salah.'], 401);
        }

        $token = $user->createToken('react-app')->plainTextToken;

        return response()->json(['token' => $token, 'nama' => $user->name]);
    }

    public function logout(Request $request)
    {
        $request->user()->currentAccessToken()->delete();
        return response()->json(['pesan' => 'Berhasil logout.']);
    }
}

Method createToken() menghasilkan token unik yang akan dipakai React untuk membuktikan identitasnya di setiap permintaan.

Melindungi Route API

Di routes/api.php, tambahkan route login dan bungkus route produk dengan middleware auth:sanctum:

use App\Http\Controllers\AuthController;

Route::post('/login', [AuthController::class, 'login']);

Route::middleware('auth:sanctum')->group(function () {
    Route::apiResource('produk', ProdukController::class);
    Route::post('/logout', [AuthController::class, 'logout']);
});

Kini seluruh endpoint produk hanya bisa diakses dengan token yang valid. Tanpa token, API akan menolak dengan status 401.

Login dari React

Buat komponen login yang menyimpan token ke localStorage:

import { useState } from 'react';
import api from './api';

function Login({ onLogin }) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();

    api.post('/login', { email, password })
      .then((res) => {
        localStorage.setItem('token', res.data.token);
        onLogin(res.data.nama);
      })
      .catch(() => setError('Email atau password salah.'));
  };

  return (
    <form onSubmit={handleSubmit}>
      <h2>Login</h2>
      {error && <div className="alert-error">{error}</div>}
      <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
      <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" />
      <button type="submit">Login</button>
    </form>
  );
}

export default Login;
Form login React (Sanctum)
Form login React (Sanctum)

Mengirim Token di Setiap Permintaan

Agar setiap permintaan otomatis membawa token, gunakan interceptor axios di src/api.js:

import axios from 'axios';

const api = axios.create({
  baseURL: 'http://localhost:8000/api',
});

// sisipkan token ke header setiap permintaan
api.interceptors.request.use((config) => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

export default api;

Header Authorization: Bearer {token} inilah yang membuktikan identitas React ke Sanctum di setiap permintaan — tanpa perlu login ulang.

Logout dan Cek Status Login

Di App.jsx, tampilkan halaman login jika belum ada token, dan sediakan tombol logout:

function App() {
  const [token, setToken] = useState(localStorage.getItem('token'));

  const logout = () => {
    api.post('/logout').finally(() => {
      localStorage.removeItem('token');
      setToken(null);
    });
  };

  if (!token) {
    return <Login onLogin={() => setToken(localStorage.getItem('token'))} />;
  }

  return (
    <div className="container">
      <button onClick={logout}>Logout</button>
      {/* daftar produk dan form */}
    </div>
  );
}

Catatan Keamanan

  • Untuk produksi, batasi allowed_origins CORS ke domain frontend yang sebenarnya.
  • Menyimpan token di localStorage praktis, tetapi untuk keamanan lebih tinggi pertimbangkan pola httpOnly cookie dengan Sanctum SPA authentication.
  • Selalu gunakan HTTPS di produksi agar token tidak bisa disadap.

Penutup Seri

Selamat! Anda telah menyelesaikan seri fullstack React + Laravel — dari membangun REST API (Part 1), menampilkan data di React (Part 2), CRUD interaktif (Part 3), hingga pencarian dan autentikasi token dengan Sanctum (Part 4). Anda kini menguasai pola pengembangan aplikasi web modern yang paling banyak dipakai di industri.

Langkah selanjutnya bisa Anda eksplorasi: React Router untuk multi-halaman, state management dengan Context atau Redux, deploy ke server, hingga upload gambar produk. Semua dibangun di atas fondasi yang sudah Anda kuasai. Selamat berkarya!

Referensi: untuk pendalaman lebih lanjut, kunjungi dokumentasi resmi React dan Laravel.

Baca Juga

Ali Akbar

Software Developer yang fokus mengembangkan aplikasi berbasis Web dan Desktop. Senang mempelajari teknologi baru terutama di bidang web design dan web development.

View all posts by Ali Akbar →

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *