Skip to main content

Command Palette

Search for a command to run...

Lucia Auth: Otentikasi Modern untuk TypeScript, Bun, dan Hono

Updated
β€’5 min read
Lucia Auth: Otentikasi Modern untuk TypeScript, Bun, dan Hono
A

I am an enthusiastic researcher and developer with a passion for using technology to innovate in business and education.

Otentikasi (authentication) adalah jantung keamanan sebuah aplikasi.
Namun, membuat sistem login dari nol sering kali merepotkan:

  • Harus mengelola hash password (bcrypt, argon2)

  • Membuat sesi aman (cookies, JWT, CSRF)

  • Mengatur login dengan provider OAuth (Google, GitHub, dst)

  • Menulis middleware untuk memeriksa user login

  • Menjamin semua berjalan aman di berbagai platform (Node.js, Edge, Bun)

Nah, Lucia Auth hadir untuk menjawab semua itu dengan prinsip:

β€œA simple and type-safe authentication library for the modern web.”


βš™οΈ Apa Itu Lucia?

Lucia adalah library otentikasi open-source berbasis TypeScript yang:

  • Ringan dan modular (tidak seperti NextAuth yang besar dan opiniated)

  • Mendukung berbagai runtime: Node.js, Bun, Deno, Cloudflare Workers

  • Tidak bergantung framework (bisa dipakai di Hono, Elysia, Next.js, SvelteKit, dll)

  • Memiliki integrasi database yang luas (Prisma, Drizzle, LibSQL, PlanetScale, dsb)

  • Fokus pada type safety, clean code, dan keamanan modern

Lucia bertujuan agar kamu bisa membuat login, register, dan session management dengan kontrol penuh, tapi tanpa boilerplate.


🧩 Arsitektur Dasar Lucia

Secara garis besar, Lucia bekerja dengan tiga komponen utama:

  1. User β€” data pengguna yang disimpan di database.

  2. Session β€” identitas sementara pengguna yang sedang login.

  3. Adapter β€” jembatan antara Lucia dan database (Prisma, Drizzle, dsb).

Client  ⇄  Server (Lucia) ⇄  Database (Drizzle/Prisma)

πŸš€ Instalasi

Contoh setup dengan Node.js / Bun dan Drizzle ORM:

npm install lucia @lucia-auth/adapter-drizzle drizzle-orm

🧱 Setup Dasar Lucia

Buat file auth.ts:

import { Lucia } from "lucia";
import { DrizzleAdapter } from "@lucia-auth/adapter-drizzle";
import { db } from "./db";
import { sessionTable, userTable } from "./schema";

export const lucia = new Lucia(new DrizzleAdapter(db, sessionTable, userTable), {
  sessionCookie: {
    name: "session",
    attributes: {
      secure: process.env.NODE_ENV === "production"
    }
  },
  getUserAttributes: (data) => ({
    username: data.username
  })
});

export type Auth = typeof lucia;

Penjelasan:

  • DrizzleAdapter menyambungkan Lucia ke database

  • sessionCookie mengatur nama cookie dan keamanannya

  • getUserAttributes menentukan data yang akan diakses di user


🧰 Skema Database

Contoh skema Drizzle:

import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";

export const userTable = pgTable("user", {
  id: text("id").primaryKey(),
  username: text("username").notNull(),
  hashed_password: text("hashed_password").notNull(),
});

export const sessionTable = pgTable("session", {
  id: text("id").primaryKey(),
  user_id: text("user_id")
    .notNull()
    .references(() => userTable.id),
  expires_at: timestamp("expires_at", { withTimezone: true }).notNull(),
});

πŸ”‘ Register (Sign Up)

import { lucia } from "./auth";
import { generateId } from "lucia";
import { Argon2id } from "oslo/password";

const passwordHasher = new Argon2id();

export async function register(username: string, password: string) {
  const userId = generateId(15);
  const hashedPassword = await passwordHasher.hash(password);

  await db.insert(userTable).values({
    id: userId,
    username,
    hashed_password: hashedPassword
  });

  const session = await lucia.createSession(userId, {});
  const sessionCookie = lucia.createSessionCookie(session.id);

  return { sessionCookie };
}

Lucia memakai library Oslo (resmi dari Lucia) untuk hashing password dengan standar tinggi seperti Argon2id β€” aman dan cepat.


πŸ” Login (Sign In)

export async function login(username: string, password: string) {
  const existingUser = await db.query.userTable.findFirst({
    where: (u, { eq }) => eq(u.username, username)
  });

  if (!existingUser) throw new Error("User not found");

  const valid = await passwordHasher.verify(
    existingUser.hashed_password,
    password
  );

  if (!valid) throw new Error("Invalid password");

  const session = await lucia.createSession(existingUser.id, {});
  const sessionCookie = lucia.createSessionCookie(session.id);

  return { sessionCookie };
}

🧾 Middleware: Memeriksa User yang Login

Lucia menyediakan cara mudah untuk memvalidasi session dari request:

import { lucia } from "./auth";

export async function getUserFromRequest(request: Request) {
  const session = await lucia.validateRequest(request);
  if (!session) return null;
  return session.user;
}

Kamu bisa gunakan fungsi ini di middleware Hono atau Next.js API Route untuk melindungi route privat.


🧠 Integrasi dengan Hono

Contoh route login sederhana:

import { Hono } from "hono";
import { login, register } from "./auth-controller";
import { lucia } from "./auth";

const app = new Hono();

app.post("/login", async (c) => {
  const { username, password } = await c.req.json();
  const { sessionCookie } = await login(username, password);
  c.header("Set-Cookie", sessionCookie.serialize());
  return c.json({ success: true });
});

app.get("/me", async (c) => {
  const auth = await lucia.validateRequest(c.req);
  if (!auth) return c.json({ user: null });
  return c.json({ user: auth.user });
});

🌍 Login dengan Google atau GitHub (OAuth)

Lucia menyediakan package resmi untuk OAuth:

npm install @lucia-auth/oauth

Contoh integrasi Google:

import { google } from "@lucia-auth/oauth/providers";
import { lucia } from "./auth";

export const googleAuth = google(lucia, {
  clientId: process.env.GOOGLE_CLIENT_ID!,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
  redirectUri: "https://example.com/api/callback/google"
});

Saat user login lewat Google:

  1. Arahkan ke googleAuth.getAuthorizationUrl()

  2. Setelah redirect, tangkap code dan panggil googleAuth.validateCallback(code)

  3. Lucia akan otomatis membuat atau menemukan user di database


πŸ”’ Keamanan Lucia

Lucia dibangun dengan prinsip keamanan tinggi:

  • Menggunakan cookie-based session, bukan JWT (lebih aman untuk web)

  • Tidak menyimpan token rahasia di localStorage

  • Sesi otomatis kadaluarsa dan dapat diperbarui

  • Password hashing menggunakan Argon2id (via Oslo)

  • Type-safe di seluruh proses


⚑ Dibandingkan Library Lain

FiturLuciaNextAuth.jsPassport.js
Framework agnosticβœ… Ya❌ Khusus Next.js⚠️ Untuk Express
Type safetyβœ… Kuat (Zod + TS)⚠️ Terbatas❌ Tidak ada
OAuth (Google, GitHub, dst)βœ… Mudahβœ… Banyak providerβœ… Banyak provider
Session cookieβœ… Built-inβœ…βš οΈ Bergantung plugin
Database bebasβœ… (Drizzle, Prisma, SQL, dll)⚠️ Perlu adapter khusus⚠️ Manual
RuntimeNode.js, Bun, Deno, CloudflareHanya Node.jsHanya Node.js
Ukuran & kontrolRingan, fleksibelBesar, opiniatedBerat & legacy

🧩 Ekosistem Pendukung

  • 🧠 Oslo – library resmi untuk hashing & crypto

  • 🧰 @lucia-auth/adapter-* – integrasi dengan ORM/DB populer

  • πŸ”— @lucia-auth/oauth – provider login sosial

  • πŸ“¦ tRPC / Hono / Elysia – backend framework yang cocok


🧾 Kesimpulan

Lucia menawarkan keseimbangan sempurna antara kemudahan, fleksibilitas, dan keamanan.

Jika kamu ingin sistem auth yang:

  • Clean, type-safe, dan tidak bergantung framework

  • Cocok untuk Bun, Hono, atau Edge Function

  • Mendukung OAuth tanpa ribet

  • Bisa diatur penuh sesuai kebutuhan

… maka Lucia adalah pilihan terbaik di ekosistem TypeScript modern.


πŸ“š Rangkuman Cepat

AspekDeskripsi
NamaLucia Auth
BahasaTypeScript
ArsitekturSession-based (bukan JWT)
ORM SupportDrizzle, Prisma, LibSQL, PlanetScale, dkk
OAuthGoogle, GitHub, Discord, Facebook, dkk
KeamananArgon2id, Cookie Secure, HttpOnly
RuntimeNode.js, Bun, Deno, Cloudflare
FilosofiSimple. Type-safe. Framework-agnostic.

More from this blog

F

Finlup ID | Sharing dunia teknologi dan coding

215 posts

Membedah Tren dan Teknologi yang Mengubah Dunia.