Most auth libraries try to do everything. Lucia does one thing well — session management. No magic, no hidden complexity, just sessions that work.
What is Lucia?
Lucia is a lightweight authentication library for TypeScript. It handles session creation, validation, and invalidation. You bring your own database and login methods. Lucia manages the session lifecycle.
Why Lucia's Approach Works
1. Minimal, Understandable API
import { Lucia } from "lucia";
import { DrizzleSQLiteAdapter } from "@lucia-auth/adapter-drizzle";
const adapter = new DrizzleSQLiteAdapter(db, sessionTable, userTable);
export const lucia = new Lucia(adapter, {
sessionCookie: {
attributes: {
secure: process.env.NODE_ENV === "production",
},
},
getUserAttributes: (attributes) => {
return { username: attributes.username };
},
});
2. Framework Agnostic
// Next.js
import { cookies } from "next/headers";
export async function getUser() {
const sessionId = cookies().get(lucia.sessionCookieName)?.value ?? null;
if (!sessionId) return null;
const { session, user } = await lucia.validateSession(sessionId);
return user;
}
// Express
app.use(async (req, res, next) => {
const sessionId = lucia.readSessionCookie(req.headers.cookie ?? "");
if (!sessionId) { req.user = null; return next(); }
const { session, user } = await lucia.validateSession(sessionId);
req.user = user;
next();
});
// SvelteKit
export const handle: Handle = async ({ event, resolve }) => {
const sessionId = event.cookies.get(lucia.sessionCookieName);
if (!sessionId) { event.locals.user = null; return resolve(event); }
const { session, user } = await lucia.validateSession(sessionId);
event.locals.user = user;
return resolve(event);
};
3. Login Implementation (You Control It)
// Sign up
app.post("/signup", async (req, res) => {
const { username, password } = req.body;
const hashedPassword = await new Argon2id().hash(password);
const userId = generateId(15);
await db.insert(userTable).values({
id: userId,
username,
hashedPassword,
});
const session = await lucia.createSession(userId, {});
const cookie = lucia.createSessionCookie(session.id);
res.setHeader("Set-Cookie", cookie.serialize());
res.redirect("/dashboard");
});
// Sign in
app.post("/signin", async (req, res) => {
const { username, password } = req.body;
const user = await db.query.userTable.findFirst({
where: eq(userTable.username, username),
});
if (!user) return res.status(401).send("Invalid credentials");
const valid = await new Argon2id().verify(user.hashedPassword, password);
if (!valid) return res.status(401).send("Invalid credentials");
const session = await lucia.createSession(user.id, {});
const cookie = lucia.createSessionCookie(session.id);
res.setHeader("Set-Cookie", cookie.serialize());
res.redirect("/dashboard");
});
4. OAuth Support
import { GitHub } from "arctic";
const github = new GitHub(clientId, clientSecret);
// Start OAuth flow
app.get("/login/github", async (req, res) => {
const state = generateState();
const url = github.createAuthorizationURL(state, ["user:email"]);
res.redirect(url.toString());
});
// Handle callback
app.get("/login/github/callback", async (req, res) => {
const tokens = await github.validateAuthorizationCode(req.query.code);
const githubUser = await fetch("https://api.github.com/user", {
headers: { Authorization: `Bearer ${tokens.accessToken}` },
}).then(r => r.json());
// Create or find user, create session...
const session = await lucia.createSession(userId, {});
// ...
});
5. Database Adapters
Supported:
- Drizzle ORM (SQLite, PostgreSQL, MySQL)
- Prisma
- Mongoose
- Better-sqlite3
- unstorage (Redis, Cloudflare KV, etc.)
Lucia vs NextAuth vs Clerk
| Lucia | NextAuth/Auth.js | Clerk | |
|---|---|---|---|
| Philosophy | Sessions only, you build login | Full auth solution | Managed service |
| Complexity | Low | Medium | Low (hosted) |
| Control | Full | Partial | Limited |
| Database | Your choice | Adapters | Managed |
| OAuth | Via Arctic | Built-in providers | Built-in |
| Lock-in | Zero | Low | High |
| Price | Free | Free | Freemium |
Getting Started
npm install lucia
npm install @lucia-auth/adapter-drizzle # or your adapter
npm install arctic # for OAuth
The Bottom Line
Lucia gives you exactly what you need for auth and nothing more. If you want to understand every line of your authentication code, Lucia is the right choice.
Need data tools? I build scraping solutions. Check my Apify actors or email spinov001@gmail.com.
Top comments (0)