A simple and flexible authentication library
Lucia is a TypeScript-first authentication library that provides low-level primitives for building custom authentication systems in Node.js applications. Unlike high-level solutions that abstract away authentication details, Lucia gives you direct control over user management, session handling, and authentication flows while remaining framework-agnostic. It works seamlessly with SvelteKit, Next.js, Express, and other JavaScript frameworks through middleware adapters.
The library implements session-based authentication by storing session IDs in secure, httpOnly cookies and validating them against database records. It supports multiple database backends through official adapters for Prisma, Drizzle ORM, MySQL, PostgreSQL, SQLite, and Redis. Lucia's key management system allows users to authenticate through multiple methods—email/password, OAuth providers, magic links—all tied to a single user account through a flexible "key" abstraction.
With nearly 100,000 weekly downloads, Lucia has gained traction among developers who need more control than all-in-one solutions provide but don't want to build authentication from scratch. However, it's important to note that as of October 2024, the maintainers announced Lucia v3 will be deprecated by March 2025, with core maintenance limited to critical bug fixes. The adapter ecosystem will be deprecated by end of 2024, though the library remains functional and widely used in production applications.
Despite the deprecation notice, Lucia remains relevant for understanding session-based authentication patterns and continues to be featured in recent tutorials and production codebases. Developers should evaluate whether to adopt it for new projects given the deprecation timeline, though existing implementations remain stable and the concepts translate well to alternative solutions.
import { lucia } from 'lucia';
import { betterSqlite3 } from '@lucia-auth/adapter-sqlite';
import sqlite from 'better-sqlite3';
const db = sqlite('auth.db');
db.exec(`
CREATE TABLE IF NOT EXISTS user (
id TEXT PRIMARY KEY,
email TEXT UNIQUE NOT NULL
);
CREATE TABLE IF NOT EXISTS session (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
expires_at INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES user(id)
);
`);
const auth = lucia({
adapter: betterSqlite3(db, {
user: 'user',
session: 'session'
}),
env: 'DEV',
getUserAttributes: (data) => {
return {
email: data.email
};
}
});
async function registerUser(email, password) {
const user = await auth.createUser({
key: {
providerId: 'email',
providerUserId: email.toLowerCase(),
password
},
attributes: {
email
}
});
return user;
}
async function loginUser(email, password) {
const key = await auth.useKey('email', email.toLowerCase(), password);
const session = await auth.createSession({
userId: key.userId,
attributes: {}
});
return { session, userId: key.userId };
}
async function validateSession(sessionId) {
const { session, user } = await auth.validateSession(sessionId);
if (!session) return null;
return { session, user };
}
const newUser = await registerUser('user@example.com', 'securePassword123');
const { session } = await loginUser('user@example.com', 'securePassword123');
const validated = await validateSession(session.sessionId);
console.log('Authenticated user:', validated.user.email);Custom authentication flows for SaaS applications: Build multi-tenant authentication systems where you need granular control over session lifetimes, user attributes, and authentication methods. Lucia's low-level primitives let you implement complex requirements like organization-scoped sessions or role-based session attributes that high-level libraries can't easily accommodate.
Multi-provider authentication portals: Create applications where users can link multiple authentication methods (email/password, GitHub, Google, magic links) to a single account. Lucia's key management system treats each auth method as a separate "key" linked to the user, making it straightforward to add or remove providers without restructuring your database.
Microservice architectures with shared sessions: Implement session validation across multiple Node.js services using a shared Redis or database backend. Lucia's framework-agnostic design and explicit session management make it suitable for distributed systems where authentication state needs to be accessible from multiple services.
Learning and prototyping authentication systems: Understand how session-based authentication works at a fundamental level without the abstraction layers of tools like Passport or Auth.js. Lucia's explicit API makes authentication mechanics transparent, making it valuable for educational purposes or when building proof-of-concept authentication systems.
Applications requiring custom session storage logic: Build systems with specialized session requirements like geographic session pinning, device fingerprinting, or custom session refresh logic. Lucia's direct database access and session primitive give you full control over how sessions are created, validated, and invalidated.
npm install luciapnpm add luciabun add lucia