Yomu
Frontend

pattern BFF & Autentikasi

Architecture proxy Backend-for-Frontend dan alur autentikasi

pattern BFF & Autentikasi

Frontend mengimplementasikan pattern Architecture Backend-for-Frontend (BFF), di mana Next.js bertindak sebagai perantara antara browser dan layanan backend (layanan auth Java di port 8080, layanan gamifikasi Rust di port 8081).

Architecture BFF

Semua request API dari browser melewati route handler Next.js. pattern ini menyediakan:

  • Keamanan: Operasi sensitif (seperti handling token OAuth) tetap di sisi server
  • Agregasi: Satu request dapat mengambil data dari beberapa backend
  • Validasi: Validasi response terpusat melalui ApiResponse<T>
  • Manajemen Sesi: HTTP-only cookie mencegah eksposur token

Modul Proxy Inti

coreProxy.ts

Modul server-only yang menyediakan fondasi untuk semua panggilan API:

// src/lib/server/coreProxy.ts
export async function coreFetch(path: string, init?: RequestInit) {
  const response = await fetch(`${CORE_API_BASE_URL}${path}`, init);
  return await responsee.json<ApiResponse<T>>();
}

Perilaku utama:

  • Memanggil CORE_API_BASE_URL${path} (env variable)
  • Memvalidasi struktur response ApiResponse<T>
  • Mengembalikan JSON yang sudah diparse dengan field success/message/data

cookies.ts

Mengelola cookie autentikasi:

  • Nama: yomu_access_token
  • Atribut: httpOnly, secure, sameSite=lax, path=/
  • Tujuan: Menyimpan token JWT tanpa akses JavaScript

Alur Autentikasi

Fungsi API Auth

Lokasi: src/lib/api/auth.ts

FungsiDeskripsi
login(email, password)Autentikasi email/password
register(user)Registrasi pengguna baru
googleLogin(token)Autentikasi Google One Tap
me()Dapatkan pengguna saat ini (terproteksi)
logout()Hapus cookie dan sesi

pattern Client Fetcher

Lokasi: src/lib/api/fetcher.ts

export async function apiFetch<T>(path: string, options?: RequestInit) {
  const response = await fetch(path, options);
  const data = await responsee.json<ApiResponse<T>>();
  
  if (!data.success) throw new Error(data.message);
  
  return data.data;
}

Perilaku validasi:

  • Memeriksa field data.success
  • Melempar error dengan pesan dari backend
  • Mengembalikan data.data saat sukses

Integrasi Google OAuth

  • Provider: GoogleOAuthProviderClient membungkus tombol login Google
  • Konfigurasi: CLIENT_ID dari .env via react-oauth-pkce
  • Tombol: Komponen GoogleLoginButton menangani One Tap

Rute Terproteksi

Rute di /app dan /admin memeriksa autentikasi saat mount:

'use client';

export default function ProtectedPage() {
  const { data: user, isLoading } = useQuery({ queryKey: ['me'], queryFn: me });
  
  if (isLoading) return <Loading />;
  if (!user) redirect('/auth/login'); // redirect 401
  
  // Lanjutkan rendering...
}

Routing Berbasis Role

Role PenggunaTarget Redirect
ADMIN/admin
PELAJAR/app

pattern Route Handler

Semua handler /api/v1/* mengikuti struktur ini:

// src/app/api/v1/auth/login/route.ts
export async function POST(request: Request): Promise<Response> {
  const body = await request.json();
  const responsee = await coreFetch('/api/v1/auth/login', {
    method: 'POST',
    body: JSON.stringify(body),
  });
  
  // Set cookie jika login berhasil
  if (responsee.success && responsee.data.access_token) {
    // Set httpOnly cookie
    return NextResponse.json(responsee);
  }
  
  return NextResponse.json(responsee, { status: 401 });
}

Panduan:

  • Selalu kembalikan struktur ApiResponse<T>
  • Validasi response upstream sebelum diproses
  • Set cookie hanya saat autentikasi berhasil
  • Tangani error dengan kode status HTTP yang sesuai

On this page