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
| Fungsi | Deskripsi |
|---|---|
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.datasaat sukses
Integrasi Google OAuth
- Provider: GoogleOAuthProviderClient membungkus tombol login Google
- Konfigurasi:
CLIENT_IDdari .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 Pengguna | Target 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