### Install Example Project Source: https://v3.lucia-auth.com/tutorials/github-oauth/nuxt Use npx to download an example project for GitHub OAuth in Nuxt. ```bash npx degit https://github.com/lucia-auth/examples/nuxt/github-oauth ``` -------------------------------- ### Install Lucia Example Project Source: https://v3.lucia-auth.com/tutorials/username-and-password/sveltekit Use npx to download an example project for username and password authentication in SvelteKit. ```bash npx degit https://github.com/lucia-auth/examples/sveltekit/username-and-password ``` -------------------------------- ### Install MySQL Adapter Source: https://v3.lucia-auth.com/database/mysql Install the @lucia-auth/adapter-mysql package using npm. ```bash npm install @lucia-auth/adapter-mysql ``` -------------------------------- ### Install Lucia Source: https://v3.lucia-auth.com/getting-started/sveltekit Install Lucia using npm. ```bash npm install -D lucia ``` -------------------------------- ### Download Example Project Source: https://v3.lucia-auth.com/tutorials/username-and-password/nextjs-pages Use npx to download the example project for username and password authentication in Next.js. ```bash npx degit https://github.com/lucia-auth/examples/nextjs-pages/username-and-password ``` -------------------------------- ### Initialize Example Project Source: https://v3.lucia-auth.com/tutorials/github-oauth/nextjs-app Use degit to scaffold a new project based on the GitHub OAuth example. ```bash npx degit https://github.com/lucia-auth/examples/nextjs-app/github-oauth ``` -------------------------------- ### Install Lucia Source: https://v3.lucia-auth.com/getting-started/nextjs-app Install the Lucia package using npm. ```bash npm install lucia ``` -------------------------------- ### Install Arctic Source: https://v3.lucia-auth.com/guides/oauth/basics Install the Arctic library to handle OAuth 2.0 provider interactions. ```bash npm install arctic ``` -------------------------------- ### Clone Example Project Source: https://v3.lucia-auth.com/tutorials/github-oauth/sveltekit Use npx to clone the example project for this tutorial. Replace with your desired project folder name. ```bash npx degit https://github.com/lucia-auth/examples/sveltekit/github-oauth ``` -------------------------------- ### Install Prisma Adapter Source: https://v3.lucia-auth.com/database/prisma Command to install the Prisma adapter package for Lucia Auth. ```bash npm install @lucia-auth/adapter-prisma ``` -------------------------------- ### Install SQLite Adapter Source: https://v3.lucia-auth.com/database/sqlite Install the required package via npm. ```bash npm install @lucia-auth/adapter-sqlite ``` -------------------------------- ### Install PostgreSQL Adapter Source: https://v3.lucia-auth.com/database/postgresql Install the required adapter package via npm. ```bash npm install @lucia-auth/adapter-postgresql ``` -------------------------------- ### Install Lucia MongoDB Adapter Source: https://v3.lucia-auth.com/database/mongoose Install the required adapter package via npm. ```bash npm install @lucia-auth/adapter-mongodb ``` -------------------------------- ### Initialize Lucia Source: https://v3.lucia-auth.com/upgrade-v3 Basic and full configuration examples for initializing the Lucia class. ```javascript import { Lucia, TimeSpan } from "lucia"; import { astro } from "lucia/middleware"; export const lucia = new Lucia(adapter, { sessionCookie: { attributes: { secure: env === "PRODUCTION" // replaces `env` config } } }); ``` ```javascript import { Lucia, TimeSpan } from "lucia"; import { astro } from "lucia/middleware"; export const lucia = new Lucia(adapter, { getSessionAttributes: (attributes) => { return { ipCountry: attributes.ip_country }; }, getUserAttributes: (attributes) => { return { username: attributes.username }; }, sessionExpiresIn: new TimeSpan(30, "d"), // no more active/idle sessionCookie: { name: "session", expires: false, // session cookies have very long lifespan (2 years) attributes: { secure: true, sameSite: "strict", domain: "example.com" } } }); ``` -------------------------------- ### Install Drizzle Adapter Source: https://v3.lucia-auth.com/database/drizzle Command to install the Lucia Drizzle adapter package. ```bash npm install @lucia-auth/adapter-drizzle ``` -------------------------------- ### Initialize Example Project Source: https://v3.lucia-auth.com/tutorials/username-and-password/astro Use degit to scaffold a new Astro project with username and password authentication pre-configured. ```bash npx degit https://github.com/lucia-auth/examples/astro/username-and-password ``` -------------------------------- ### Initialize Example Project Source: https://v3.lucia-auth.com/tutorials/username-and-password/nuxt Use degit to scaffold a new Nuxt project with username and password authentication pre-configured. ```bash npx degit https://github.com/lucia-auth/examples/nuxt/username-and-password ``` -------------------------------- ### Initialize project template Source: https://v3.lucia-auth.com/tutorials/github-oauth/astro Use degit to scaffold a new project based on the GitHub OAuth example. ```bash npx degit https://github.com/lucia-auth/examples/astro/github-oauth ``` -------------------------------- ### Install MySQL Adapter Source: https://v3.lucia-auth.com/upgrade-v3/mysql Install the latest version of the MySQL adapter package using npm. ```bash npm install @lucia-auth/adapter-mysql ``` -------------------------------- ### Initialize project with degit Source: https://v3.lucia-auth.com/tutorials/github-oauth/nextjs-pages Use degit to scaffold a new project based on the GitHub OAuth example. ```bash npx degit https://github.com/lucia-auth/examples/nextjs-pages/github-oauth ``` -------------------------------- ### Initialize Prisma Adapter Source: https://v3.lucia-auth.com/database/prisma Setup the PrismaAdapter by passing the session and user models from the Prisma client. ```typescript import { PrismaAdapter } from "@lucia-auth/adapter-prisma"; import { PrismaClient } from "@prisma/client"; const client = new PrismaClient(); const adapter = new PrismaAdapter(client.session, client.user); ``` -------------------------------- ### Install MongoDB Adapter for Lucia Source: https://v3.lucia-auth.com/upgrade-v3/mongoose Install the MongoDB adapter package using npm. This is the first step to integrate Lucia v3 with MongoDB. ```bash npm install @lucia-auth/adapter-mongodb ``` -------------------------------- ### Install Oslo library Source: https://v3.lucia-auth.com/guides/email-and-password Install the Oslo library, which provides authentication utilities used by Lucia. ```bash npm i oslo ``` -------------------------------- ### Install Lucia and Oslo Source: https://v3.lucia-auth.com/upgrade-v3 Command to install the core Lucia library and the recommended Oslo utility library. ```bash npm install lucia oslo ``` -------------------------------- ### Cookie Usage Example Source: https://v3.lucia-auth.com/reference/main/Cookie Examples of how to instantiate and use the Cookie class in a web framework. ```APIDOC ### Request Example ```javascript import { Cookie } from "lucia"; const sessionCookie = new Cookie("session", sessionId, { maxAge: 60 * 60 * 24, httpOnly: true, secure: true, path: "/" }); response.headers.set("Set-Cookie", sessionCookie.serialize()); ``` ``` -------------------------------- ### LegacyScrypt Usage Example Source: https://v3.lucia-auth.com/reference/main/LegacyScrypt Demonstrates initializing the class and performing password hashing and verification. ```typescript import { LegacyScrypt } from "lucia"; const scrypt = new LegacyScrypt(); const hash = await scrypt.hash(password); const validPassword = await scrypt.verify(hash, password); ``` -------------------------------- ### Install Arctic Package Source: https://v3.lucia-auth.com/upgrade-v3/oauth Install the Arctic package using npm. This package replaces the previous Lucia-specific OAuth integration. ```bash npm install arctic ``` -------------------------------- ### Usage of LegacyScrypt.hash() Source: https://v3.lucia-auth.com/reference/main/LegacyScrypt/hash Example showing how to call the hash method with a password string. ```javascript const hash = await scrypt.hash(password); ``` -------------------------------- ### Verify password with LegacyScrypt Source: https://v3.lucia-auth.com/reference/main/LegacyScrypt/verify Usage example for verifying a password using the scrypt verify method. ```javascript const validPassword = await scrypt.verify(hash, password); ``` -------------------------------- ### Setup Server Handle Hook Source: https://v3.lucia-auth.com/getting-started/sveltekit Implement a SvelteKit handle hook to validate incoming requests using Lucia. This hook sets `event.locals.user` and `event.locals.session` based on the session cookie. ```typescript // src/hooks.server.ts import { lucia } from "$lib/server/auth"; import type { Handle } from "@sveltejs/kit"; export const handle: Handle = async ({ event, resolve }) => { const sessionId = event.cookies.get(lucia.sessionCookieName); if (!sessionId) { event.locals.user = null; event.locals.session = null; return resolve(event); } const { session, user } = await lucia.validateSession(sessionId); if (session && session.fresh) { const sessionCookie = lucia.createSessionCookie(session.id); // sveltekit types deviates from the de-facto standard // you can use 'as any' too event.cookies.set(sessionCookie.name, sessionCookie.value, { path: ".", ...sessionCookie.attributes }); } if (!session) { const sessionCookie = lucia.createBlankSessionCookie(); event.cookies.set(sessionCookie.name, sessionCookie.value, { path: ".", ...sessionCookie.attributes }); } event.locals.user = user; event.locals.session = session; return resolve(event); }; ``` -------------------------------- ### Implement sign-up server action Source: https://v3.lucia-auth.com/tutorials/username-and-password/nextjs-app Handle form submission, validate inputs, hash the password, and create a session. ```typescript import { db } from "@/lib/db"; import { hash } from "@node-rs/argon2"; import { cookies } from "next/headers"; import { lucia } from "@/lib/auth"; import { redirect } from "next/navigation"; import { generateIdFromEntropySize } from "lucia"; export default async function Page() {} async function signup(_: any, formData: FormData): Promise { "use server"; const username = formData.get("username"); // username must be between 4 ~ 31 characters, and only consists of lowercase letters, 0-9, -, and _ // keep in mind some database (e.g. mysql) are case insensitive if ( typeof username !== "string" || username.length < 3 || username.length > 31 || !/^[a-z0-9_-]+$/.test(username) ) { return { error: "Invalid username" }; } const password = formData.get("password"); if (typeof password !== "string" || password.length < 6 || password.length > 255) { return { error: "Invalid password" }; } const passwordHash = await hash(password, { // recommended minimum parameters memoryCost: 19456, timeCost: 2, outputLen: 32, parallelism: 1 }); const userId = generateIdFromEntropySize(10); // 16 characters long // TODO: check if username is already used await db.table("user").insert({ id: userId, username: username, password_hash: passwordHash }); const session = await lucia.createSession(userId, {}); const sessionCookie = lucia.createSessionCookie(session.id); cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes); return redirect("/"); } ``` -------------------------------- ### Initialize Lucia project Source: https://v3.lucia-auth.com/tutorials/username-and-password/nextjs-app Use degit to scaffold a new Next.js project with Lucia username and password authentication. ```bash npx degit https://github.com/lucia-auth/examples/nextjs-app/username-and-password ``` -------------------------------- ### Hashing and Verifying Passwords with Scrypt Source: https://v3.lucia-auth.com/reference/main/Scrypt Demonstrates initializing the Scrypt class and performing password hashing and verification. ```javascript import { Scrypt } from "lucia"; const scrypt = new Scrypt(); const hash = await scrypt.hash(password); const validPassword = await scrypt.verify(hash, password); ``` -------------------------------- ### Get All User Sessions Source: https://v3.lucia-auth.com/basics/sessions Retrieves a list of all active sessions for a given user. ```APIDOC ## Get All User Sessions ### Description Returns an array of all valid sessions for a user. Returns an empty array if the user does not exist or has no active sessions. ### Method GET ### Parameters #### Query Parameters - **userId** (string) - Required - The ID of the user to fetch sessions for. ### Response #### Success Response (200) - **sessions** (array) - A list of session objects. ``` -------------------------------- ### Initialize LibSQL Adapter Source: https://v3.lucia-auth.com/database/sqlite Initialize the adapter using a LibSQL client instance. ```typescript import { Lucia } from "lucia"; import { LibSQLAdapter } from "@lucia-auth/adapter-sqlite"; import { createClient } from "@libsql/client"; const db = createClient({ url: "file:test/main.db" }); const adapter = new LibSQLAdapter(db, { user: "user", session: "session" }); ``` -------------------------------- ### Get TimeSpan in milliseconds Source: https://v3.lucia-auth.com/reference/main/TimeSpan/milliseconds Returns the total duration of the TimeSpan object as a number of milliseconds. ```typescript function milliseconds(): number; ``` ```javascript // 60 * 1000 = 60,000 ms new TimeSpan("60", "s").milliseconds(); ``` -------------------------------- ### GET /users/:userId/sessions Source: https://v3.lucia-auth.com/reference/main/Lucia/getUserSessions Retrieves all active sessions associated with a specific user ID. ```APIDOC ## GET /users/:userId/sessions ### Description Gets all sessions of a user. ### Method GET ### Endpoint /users/:userId/sessions ### Parameters #### Path Parameters - **userId** (UserId) - Required - The ID of the user whose sessions are to be retrieved. ### Response #### Success Response (200) - **sessions** (Session[]) - An array of session objects belonging to the user. ``` -------------------------------- ### Initialize Lucia and Create/Validate Session Source: https://v3.lucia-auth.com/ This snippet shows how to initialize Lucia with an adapter and then create and validate a user session. Ensure you have a database adapter configured. ```typescript import { Lucia } from "lucia"; const lucia = new Lucia(new Adapter(db)); const session = await lucia.createSession(userId, {}); await lucia.validateSession(session.id); ``` -------------------------------- ### Use session validation in getServerSideProps Source: https://v3.lucia-auth.com/guides/validate-session-cookies/nextjs-pages Example of protecting a page by validating the session within getServerSideProps. ```typescript import type { GetServerSidePropsContext } from "next"; export function getServerSideProps(context: GetServerSidePropsContext) { const user = await validateRequest(context.req, context.res); if (!user) { return { redirect: { destination: "/login", permanent: false } }; } // ... ``` -------------------------------- ### Initialize MySQL Adapters Source: https://v3.lucia-auth.com/upgrade-v3/mysql Initialize the Mysql2Adapter or PlanetScaleAdapter with your database pool/connection and table names. ```typescript import { Mysql2Adapter, PlanetScaleAdapter } from "@lucia-auth/adapter-mysql"; new Mysql2Adapter(pool, { // table names user: "user", session: "user_session" }); new PlanetScaleAdapter(connection, { // table names user: "user", session: "user_session" }); ``` -------------------------------- ### Configure Lucia with Kysely and SQLite Source: https://v3.lucia-auth.com/database/kysely Use the BetterSqlite3Adapter with a better-sqlite3 database instance. ```typescript import { Lucia } from "lucia"; import { BetterSqlite3Adapter } from "@lucia-auth/adapter-sqlite"; import sqlite from "better-sqlite3"; import { Kysely, SqliteDialect } from "kysely"; const sqliteDatabase = sqlite(); export const db = new Kysely({ dialect: new SqliteDialect({ database: sqliteDatabase }) }); const adapter = new BetterSqlite3Adapter(sqliteDatabase, tableNames); interface Database { user: UserTable; session: SessionTable; } interface UserTable { id: string; } interface SessionTable { id: string; user_id: string; expires_at: number; } ``` -------------------------------- ### Store User Password Hash Source: https://v3.lucia-auth.com/upgrade-v3 Example of hashing a password and inserting a new user record into the database. ```javascript const passwordHash = await hash(password, { // recommended minimum parameters memoryCost: 19456, timeCost: 2, outputLen: 32, parallelism: 1 }); const userId = generateIdFromEntropySize(10); // 16 characters long await db.table("user").insert({ id: userId, email, password_hash: passwordHash }); ``` -------------------------------- ### Implement User Sign-in Route Source: https://v3.lucia-auth.com/guides/email-and-password/basics Handles POST requests to `/login`, verifies email and password, and creates a Lucia session. Includes security notes on preventing timing attacks and recommendations for brute-force protection. ```typescript import { lucia } from "./auth.js"; import { verify } from "@node-rs/argon2"; app.post("/login", async (request: Request) => { const formData = await request.formData(); const email = formData.get("email"); if (!email || typeof email !== "string") { return new Response("Invalid email", { status: 400 }); } const password = formData.get("password"); if (!password || typeof password !== "string") { return new Response(null, { status: 400 }); } const user = await db.table("user").where("email", "=", email).get(); if (!user) { // NOTE: // Returning immediately allows malicious actors to figure out valid emails from response times, // allowing them to only focus on guessing passwords in brute-force attacks. // As a preventive measure, you may want to hash passwords even for invalid emails. // However, valid emails can be already be revealed with the signup page // and a similar timing issue can likely be found in password reset implementation. // It will also be much more resource intensive. // Since protecting against this is non-trivial, // it is crucial your implementation is protected against brute-force attacks with login throttling etc. // If emails/usernames are public, you may outright tell the user that the username is invalid. return new Response("Invalid email or password", { status: 400 }); } const validPassword = await verify(user.password_hash, password, { memoryCost: 19456, timeCost: 2, outputLen: 32, parallelism: 1 }); if (!validPassword) { return new Response("Invalid email or password", { status: 400 }); } const session = await lucia.createSession(user.id, {}); const sessionCookie = lucia.createSessionCookie(session.id); return new Response(null, { status: 302, headers: { Location: "/", "Set-Cookie": sessionCookie.serialize() } }); }); ``` -------------------------------- ### Initialize Lucia instance Source: https://v3.lucia-auth.com/getting-started/astro Configure the Lucia instance with a database adapter and session cookie settings. ```typescript // src/auth.ts import { Lucia } from "lucia"; const adapter = new BetterSQLite3Adapter(db); // your adapter export const lucia = new Lucia(adapter, { sessionCookie: { attributes: { // set to `true` when using HTTPS secure: import.meta.env.PROD } } }); declare module "lucia" { interface Register { Lucia: typeof lucia; } } ``` -------------------------------- ### Configure Lucia instance Source: https://v3.lucia-auth.com/tutorials/github-oauth/nextjs-pages Initialize Lucia with database attributes for GitHub user data. ```typescript import { Lucia } from "lucia"; export const lucia = new Lucia(adapter, { sessionCookie: { attributes: { secure: process.env.NODE_ENV === "production" } }, getUserAttributes: (attributes) => { return { // attributes has the type of DatabaseUserAttributes githubId: attributes.github_id, username: attributes.username }; } }); declare module "lucia" { interface Register { Lucia: typeof lucia; DatabaseUserAttributes: DatabaseUserAttributes; } } interface DatabaseUserAttributes { github_id: number; username: string; } ``` -------------------------------- ### Configure SQLite Adapter Source: https://v3.lucia-auth.com/database/drizzle Setup for DrizzleSQLiteAdapter using better-sqlite3. Session ID must be a string type. ```typescript import { DrizzleSQLiteAdapter } from "@lucia-auth/adapter-drizzle"; import sqlite from "better-sqlite3"; import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core"; import { drizzle } from "drizzle-orm/better-sqlite3"; const sqliteDB = sqlite(":memory:"); const db = drizzle(sqliteDB); const userTable = sqliteTable("user", { id: text("id").primaryKey() }); const sessionTable = sqliteTable("session", { id: text("id").primaryKey(), userId: text("user_id") .notNull() .references(() => userTable.id), expiresAt: integer("expires_at").notNull() }); const adapter = new DrizzleSQLiteAdapter(db, sessionTable, userTable); ``` -------------------------------- ### Initialize Postgres.js Adapter Source: https://v3.lucia-auth.com/database/postgresql Configure the PostgresJsAdapter using a postgres Sql instance. ```typescript import { Lucia } from "lucia"; import { PostgresJsAdapter } from "@lucia-auth/adapter-postgresql"; import postgres from "postgres"; const sql = postgres(); const adapter = new PostgresJsAdapter(sql, { user: "auth_user", session: "user_session" }); ``` -------------------------------- ### Configure PostgreSQL Adapter Source: https://v3.lucia-auth.com/database/drizzle Setup for DrizzlePostgreSQLAdapter using node-postgres. Session ID must be a string type. ```typescript import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle"; import pg from "pg"; import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { drizzle } from "drizzle-orm/node-postgres"; const pool = new pg.Pool(); const db = drizzle(pool); const userTable = pgTable("user", { id: text("id").primaryKey() }); const sessionTable = pgTable("session", { id: text("id").primaryKey(), userId: text("user_id") .notNull() .references(() => userTable.id), expiresAt: timestamp("expires_at", { withTimezone: true, mode: "date" }).notNull() }); const adapter = new DrizzlePostgreSQLAdapter(db, sessionTable, userTable); ``` -------------------------------- ### Initialize Neon HTTP Adapter Source: https://v3.lucia-auth.com/database/postgresql Configure the NeonHTTPAdapter using the @neondatabase/serverless driver. ```typescript import { Lucia } from "lucia"; import { NeonHTTPAdapter } from "@lucia-auth/adapter-postgresql"; import { neon } from "@neondatabase/serverless"; const sql = neon(); const adapter = new NeonHTTPAdapter(sql, { user: "auth_user", session: "user_session" }); ``` -------------------------------- ### Initialize GitHub provider Source: https://v3.lucia-auth.com/tutorials/github-oauth/nextjs-pages Create the GitHub provider instance using Arctic. ```typescript import { GitHub } from "arctic"; export const github = new GitHub(process.env.GITHUB_CLIENT_ID!, process.env.GITHUB_CLIENT_SECRET!); ``` -------------------------------- ### Use session validation in API route handlers Source: https://v3.lucia-auth.com/guides/validate-session-cookies/nextjs-pages Example of protecting an API route handler by validating the session. ```typescript import type { NextApiRequest, NextApiResponse } from "next"; async function handler(req: NextApiRequest, res: NextApiResponse) { const user = await validateRequest(req, res); if (!user) { return res.status(401).end(); } } export default handler; ``` -------------------------------- ### Configure Lucia with Kysely and PostgreSQL Source: https://v3.lucia-auth.com/database/kysely Use the NodePostgresAdapter with a pg Pool instance. ```typescript import { Lucia } from "lucia"; import { NodePostgresAdapter } from "@lucia-auth/adapter-postgresql"; import { Pool } from "pg"; import { Kysely, PostgresDialect } from "kysely"; const pool = new Pool(); const db = new Kysely({ dialect: new PostgresDialect({ pool }) }); const adapter = new NodePostgresAdapter(pool, tableNames); interface Database { user: UserTable; session: SessionTable; } interface UserTable { id: string; } interface SessionTable { id: string; user_id: string; expires_at: Date; } ``` -------------------------------- ### Validate Session Source: https://v3.lucia-auth.com/upgrade-v3 Example of validating a session, which now returns an object containing user and session data instead of throwing errors. ```javascript // v3 const { session, user } = await auth.validateSession(sessionId); if (!session) { // invalid session } ``` -------------------------------- ### Initialize MongoDB Adapter Source: https://v3.lucia-auth.com/database/mongodb Set up the MongoDB adapter by providing your session and user collections. Ensure your user ID can be numeric or an object ID, but session IDs must be strings. ```typescript import { Lucia } from "lucia"; import { MongodbAdapter } from "@lucia-auth/adapter-mongodb"; import { Collection, MongoClient } from "mongodb"; const client = new MongoClient(); await client.connect(); const db = client.db(); const User = db.collection("users") as Collection; const Session = db.collection("sessions") as Collection; const adapter = new MongodbAdapter(Session, User); interface UserDoc { _id: string; } interface SessionDoc { _id: string; expires_at: Date; user_id: string; } ``` -------------------------------- ### Get all user sessions Source: https://v3.lucia-auth.com/basics/sessions Retrieve an array of all valid sessions for a given user. Returns an empty array if the user does not exist. ```javascript const sessions = await lucia.getUserSessions(userId); ``` -------------------------------- ### Get TimeSpan in Seconds Source: https://v3.lucia-auth.com/reference/main/TimeSpan/seconds Converts a TimeSpan object to its equivalent in seconds. Use this when you need a precise numerical representation of a duration in seconds. ```typescript function seconds(): number; ``` ```typescript // 60 * 60 = 3600 s new TimeSpan(1, "h").seconds(); ``` -------------------------------- ### Handle User Signup with Verification Source: https://v3.lucia-auth.com/guides/email-and-password/email-verification-codes Initialize user account with unverified status and trigger the verification flow. ```typescript import { generateIdFromEntropySize } from "lucia"; app.post("/signup", async () => { // ... const userId = generateIdFromEntropySize(10); // 16 characters long await db.table("user").insert({ id: userId, email, password_hash: passwordHash, email_verified: false }); const verificationCode = await generateEmailVerificationCode(userId, email); await sendVerificationCode(email, verificationCode); const session = await lucia.createSession(userId, {}); const sessionCookie = lucia.createSessionCookie(session.id); return new Response(null, { status: 302, headers: { Location: "/", "Set-Cookie": sessionCookie.serialize() } }); }); ``` -------------------------------- ### Get Session Cookie Name Source: https://v3.lucia-auth.com/guides/validate-session-cookies Retrieve the session cookie name using `Lucia.sessionCookieName`. This is useful when integrating with framework-specific cookie utilities. ```typescript const sessionId = getCookie(lucia.sessionCookieName); ``` -------------------------------- ### Initialize GitHub Provider with Arctic Source: https://v3.lucia-auth.com/tutorials/github-oauth/sveltekit Initialize the GitHub provider from the Arctic library in your auth configuration file. Use environment variables for client ID and secret. ```typescript // src/lib/server/auth.ts // ... import { GitHub } from "arctic"; import { GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET } from "$env/static/private"; export const github = new GitHub(GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET); ``` -------------------------------- ### Define Login Page Structure Source: https://v3.lucia-auth.com/tutorials/username-and-password/nextjs-app Basic setup for a login page using a Next.js server action to handle form submission. ```typescript // app/login/page.tsx export default async function Page() { return ( <>

Sign in



); } async function login(_: any, formData: FormData): Promise {} interface ActionResult { error: string; } ``` -------------------------------- ### Initialize Bun SQLite Adapter Source: https://v3.lucia-auth.com/database/sqlite Initialize the adapter using a Bun SQLite database instance. ```typescript import { Lucia } from "lucia"; import { BunSQLiteAdapter } from "@lucia-auth/adapter-sqlite"; import { Database } from "bun:sqlite"; const db = new Database(); const adapter = new BunSQLiteAdapter(db, { user: "user", session: "session" }); ``` -------------------------------- ### Configure MySQL Adapter Source: https://v3.lucia-auth.com/database/drizzle Setup for DrizzleMySQLAdapter using mysql2. Ensure the session ID column supports at least 40 characters. ```typescript import { DrizzleMySQLAdapter } from "@lucia-auth/adapter-drizzle"; import mysql from "mysql2/promise"; import { mysqlTable, varchar, datetime } from "drizzle-orm/mysql-core"; import { drizzle } from "drizzle-orm/mysql2"; const connection = await mysql.createConnection(); const db = drizzle(connection); const userTable = mysqlTable("user", { id: varchar("id", { length: 255 }).primaryKey() }); const sessionTable = mysqlTable("session", { id: varchar("id", { length: 255 }).primaryKey(), userId: varchar("user_id", { length: 255 }) .notNull() .references(() => userTable.id), expiresAt: datetime("expires_at").notNull() }); const adapter = new DrizzleMySQLAdapter(db, sessionTable, userTable); ``` -------------------------------- ### Initialize Prisma Adapter Source: https://v3.lucia-auth.com/upgrade-v3/prisma Import the Prisma client and adapter, then instantiate the adapter with the session and user models. ```typescript import { PrismaClient } from "@prisma/client"; import { PrismaAdapter } from "@lucia-auth/adapter-prisma"; const client = new PrismaClient(); new PrismaAdapter(client.session, client.user); ``` -------------------------------- ### Get User Sessions Source: https://v3.lucia-auth.com/reference/main/Lucia/getUserSessions Use this method to retrieve all active sessions associated with a specific user ID. Ensure the `UserId` type is correctly defined. ```typescript function getUserSessions(userId: UserId): Promise; ``` -------------------------------- ### Initialize Lucia Instance Source: https://v3.lucia-auth.com/getting-started/nextjs-app Configure the Lucia instance with a database adapter and session cookie settings. Ensure the Lucia instance is registered in the module declaration. ```typescript // src/auth.ts import { Lucia } from "lucia"; const adapter = new BetterSQLite3Adapter(db); // your adapter export const lucia = new Lucia(adapter, { sessionCookie: { // this sets cookies with super long expiration // since Next.js doesn't allow Lucia to extend cookie expiration when rendering pages expires: false, attributes: { // set to `true` when using HTTPS secure: process.env.NODE_ENV === "production" } } }); // IMPORTANT! declare module "lucia" { interface Register { Lucia: typeof lucia; } } ``` -------------------------------- ### Create and Set a Session Cookie Source: https://v3.lucia-auth.com/reference/main/Cookie Example of creating a new Cookie instance with common attributes like maxAge, httpOnly, secure, and path, then setting it on the response headers. ```typescript import { Cookie } from "lucia"; const sessionCookie = new Cookie("session", sessionId, { maxAge: 60 * 60 * 24, httpOnly: true, secure: true, path: "/" }); response.headers.set("Set-Cookie", sessionCookie.serialize()); ``` -------------------------------- ### Initialize Lucia Source: https://v3.lucia-auth.com/getting-started/nuxt Configure the Lucia instance with your database adapter and session cookie settings, and register the instance type. ```typescript // server/utils/auth.ts import { Lucia } from "lucia"; const adapter = new BetterSQLite3Adapter(db); // your adapter export const lucia = new Lucia(adapter, { sessionCookie: { // IMPORTANT! attributes: { // set to `true` when using HTTPS secure: !process.dev } } }); // IMPORTANT! declare module "lucia" { interface Register { Lucia: typeof lucia; } } ``` -------------------------------- ### Use `validateRequest` in `getServerSideProps` Source: https://v3.lucia-auth.com/tutorials/username-and-password/nextjs-pages This example demonstrates how to use the `validateRequest` function within Next.js `getServerSideProps` to protect server-side rendered pages. It redirects unauthenticated users to the login page. ```typescript import { validateRequest } from "@/lib/auth"; import type { GetServerSidePropsContext, GetServerSidePropsResult, InferGetServerSidePropsType } from "next"; import type { User } from "lucia"; export async function getServerSideProps(context: GetServerSidePropsContext): Promise< GetServerSidePropsResult<{ user: User; }> > { const { user } = await validateRequest(context.req, context.res); if (!user) { return { redirect: { permanent: false, destination: "/login" } }; } return { props: { user } }; } export default function Page({ user }: InferGetServerSidePropsType) { return

Hi, {user.username}!

; } ``` -------------------------------- ### Configure Lucia with Kysely and MySQL Source: https://v3.lucia-auth.com/database/kysely Use the Mysql2Adapter with a mysql2 pool. Ensure the pool property is accessed correctly from the pool object. ```typescript import { Lucia } from "lucia"; import { Mysql2Adapter } from "@lucia-auth/adapter-mysql"; import { createPool } from "mysql2/promise"; import { Kysely, MysqlDialect } from "kysely"; const pool = createPool(); const db = new Kysely({ dialect: new MysqlDialect({ pool: pool.pool // IMPORTANT NOT TO JUST PASS `pool` }) }); const adapter = new Mysql2Adapter(pool, tableNames); interface Database { user: UserTable; session: SessionTable; } interface UserTable { id: string; } interface SessionTable { id: string; user_id: string; expires_at: Date; } ``` -------------------------------- ### Create Blank Session Cookie Source: https://v3.lucia-auth.com/reference/main/Lucia/createBlankSessionCookie Use this method to create a cookie that expires immediately, effectively deleting the session cookie. No setup or imports are required beyond having an instance of Lucia. ```typescript function createBlankSessionCookie(): Cookie; ``` -------------------------------- ### Initialize Lucia Source: https://v3.lucia-auth.com/getting-started/nextjs-pages Configure the Lucia instance with a database adapter and session cookie settings. Ensure the Lucia instance type is registered. ```typescript // src/auth.ts import { Lucia } from "lucia"; const adapter = new BetterSQLite3Adapter(db); // your adapter export const lucia = new Lucia(adapter, { sessionCookie: { attributes: { // set to `true` when using HTTPS secure: process.env.NODE_ENV === "production" } } }); // IMPORTANT! declare module "lucia" { interface Register { Lucia: typeof lucia; } } ``` -------------------------------- ### Accessing Authenticated User in API Routes Source: https://v3.lucia-auth.com/guides/validate-session-cookies/nuxt This example shows how to check for an authenticated user within an API route handler. It throws a 401 error if no user is found in the event context. ```typescript export default defineEventHandler(async (event) => { if (!event.context.user) { throw createError({ statusCode: 401 }); } // ... }); ``` -------------------------------- ### Handle User Signup and Token Generation Source: https://v3.lucia-auth.com/guides/email-and-password/email-verification-links Create a new user, generate a verification token, and send the verification email during the signup process. ```typescript import { generateIdFromEntropySize } from "lucia"; app.post("/signup", async () => { // ... const userId = generateIdFromEntropySize(10); // 16 characters long await db.table("user").insert({ id: userId, email, password_hash: passwordHash, email_verified: false }); const verificationToken = await createEmailVerificationToken(userId, email); const verificationLink = "http://localhost:3000/email-verification/" + verificationToken; await sendVerificationEmail(email, verificationLink); const session = await lucia.createSession(userId, {}); const sessionCookie = lucia.createSessionCookie(session.id); return new Response(null, { status: 302, headers: { Location: "/", "Set-Cookie": sessionCookie.serialize() } }); }); ``` -------------------------------- ### Implement Signup API Route Source: https://v3.lucia-auth.com/tutorials/username-and-password/nuxt Handle user registration by validating input, hashing passwords with Argon2, and creating a session. ```typescript // server/api/signup.post.ts import { hash } from "@node-rs/argon2"; import { generateIdFromEntropySize } from "lucia"; import { SqliteError } from "better-sqlite3"; export default eventHandler(async (event) => { const formData = await readFormData(event); const username = formData.get("username"); if ( typeof username !== "string" || username.length < 3 || username.length > 31 || !/^[a-z0-9_-]+$/.test(username) ) { throw createError({ message: "Invalid username", statusCode: 400 }); } const password = formData.get("password"); if (typeof password !== "string" || password.length < 6 || password.length > 255) { throw createError({ message: "Invalid password", statusCode: 400 }); } const passwordHash = await hash(password, { // recommended minimum parameters memoryCost: 19456, timeCost: 2, outputLen: 32, parallelism: 1 }); const userId = generateIdFromEntropySize(10); // 16 characters long // TODO: check if username is already used await db.table("user").insert({ id: userId, username: username, password_hash: passwordHash }); const session = await lucia.createSession(userId, {}); appendHeader(event, "Set-Cookie", lucia.createSessionCookie(session.id).serialize()); }); ``` -------------------------------- ### Override User ID Type Source: https://v3.lucia-auth.com/basics/users To use a user ID type other than string (e.g., number), declare `Register.UserId` in the Lucia module augmentation. This example shows how to set the user ID type to number. ```typescript declare module "lucia" { interface Register { Lucia: typeof lucia; UserId: number; } } const session = await lucia.createSession(0, {}); ``` -------------------------------- ### Using validateRequest in Next.js getServerSideProps Source: https://v3.lucia-auth.com/tutorials/github-oauth/nextjs-pages This example demonstrates how to use the `validateRequest` function within `getServerSideProps` to protect a page. If no authenticated user is found, the user is redirected to the login page. This ensures that only logged-in users can access the protected content. ```typescript import { validateRequest } from "@/lib/auth"; import type { GetServerSidePropsContext, GetServerSidePropsResult, InferGetServerSidePropsType } from "next"; import type { User } from "lucia"; export async function getServerSideProps(context: GetServerSidePropsContext): Promise< GetServerSidePropsResult<{ user: User; }> > { const { user } = await validateRequest(context.req, context.res); if (!user) { return { redirect: { permanent: false, destination: "/login" } }; } return { props: { user } }; } export default function Page({ user }: InferGetServerSidePropsType) { return

Hi, {user.username}!

; } ``` -------------------------------- ### Initialize GitHub provider Source: https://v3.lucia-auth.com/tutorials/github-oauth/astro Create a GitHub provider instance using environment variables. ```typescript import { GitHub } from "arctic"; export const github = new GitHub( import.meta.env.GITHUB_CLIENT_ID, import.meta.env.GITHUB_CLIENT_SECRET ); ``` -------------------------------- ### Create TimeSpan Instances Source: https://v3.lucia-auth.com/reference/main/TimeSpan Import and use the TimeSpan class to create instances representing various durations. Examples show creation for half seconds, ten seconds, half an hour, one hour, one day, and one week. ```typescript import { TimeSpan } from "oslo"; const halfSeconds = new TimeSpan(500, "ms"); const tenSeconds = new TimeSpan(10, "s"); const halfHour = new TimeSpan(30, "m"); const oneHour = new TimeSpan(1, "h"); const oneDay = new TimeSpan(1, "d"); const oneWeek = new TimeSpan(1, "w"); ``` -------------------------------- ### Configure Mysql2 Adapter Source: https://v3.lucia-auth.com/database/mysql Initialize the Mysql2Adapter with a mysql2/promises Pool or Connection instance and table names. ```typescript import { Lucia } from "lucia"; import { Mysql2Adapter } from "@lucia-auth/adapter-mysql"; import mysql from "mysql2/promise"; const pool = mysql.createPool(); const adapter = new Mysql2Adapter(pool, { user: "user", session: "user_session" }); ``` -------------------------------- ### Use `validateRequest` in Server Components Source: https://v3.lucia-auth.com/tutorials/github-oauth/nextjs-app This example demonstrates how to use the `validateRequest` function within a server component to fetch the current user's session. If no user is authenticated, the user is redirected to the login page. This pattern is useful for protecting routes and personalizing user experiences. ```typescript import { redirect } from "next/navigation"; import { validateRequest } from "@/lib/auth"; export default async function Page() { const { user } = await validateRequest(); if (!user) { return redirect("/login"); } return

Hi, {user.username}!

; } ``` -------------------------------- ### Initialize Cloudflare D1 Adapter Source: https://v3.lucia-auth.com/database/sqlite Initialize the adapter for Cloudflare D1, creating a new Lucia instance per request. ```typescript import { Lucia } from "lucia"; import { D1Adapter } from "@lucia-auth/adapter-sqlite"; export function initializeLucia(D1: D1Database) { const adapter = new D1Adapter(D1, { user: "user", session: "session" }); return new Lucia(adapter); } declare module "lucia" { interface Register { Lucia: ReturnType; } } ``` -------------------------------- ### Validate Session Cookies in Next.js App Router Source: https://v3.lucia-auth.com/guides/validate-session-cookies/nextjs-app Get the session cookie name using `Lucia.sessionCookieName` and validate the session with `Lucia.validateSession()`. Delete invalid cookies and refresh expired ones. Wrap in try/catch for Next.js rendering limitations. Recommended to wrap with `cache()` for performance. ```typescript import { lucia } from "@/utils/auth"; import { cookies } from "next/headers"; const getUser = cache(async () => { const sessionId = cookies().get(lucia.sessionCookieName)?.value ?? null; if (!sessionId) return null; const { user, session } = await lucia.validateSession(sessionId); try { if (session && session.fresh) { const sessionCookie = lucia.createSessionCookie(session.id); cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes); } if (!session) { const sessionCookie = lucia.createBlankSessionCookie(); cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes); } } catch { // Next.js throws error when attempting to set cookies when rendering page } return user; }); ``` -------------------------------- ### Initialize Lucia Instance Source: https://v3.lucia-auth.com/getting-started/sveltekit Initialize the Lucia instance with your database adapter and configure session cookie attributes. Ensure the `secure` attribute is set correctly based on your environment. ```typescript // src/lib/server/auth.ts import { Lucia } from "lucia"; import { dev } from "$app/environment"; const adapter = new BetterSQLite3Adapter(db); // your adapter export const lucia = new Lucia(adapter, { sessionCookie: { attributes: { // set to `true` when using HTTPS secure: !dev } } }); declare module "lucia" { interface Register { Lucia: typeof lucia; } } ``` -------------------------------- ### Configure PlanetScale Serverless Adapter Source: https://v3.lucia-auth.com/database/mysql Initialize the PlanetScaleAdapter with a PlanetScale Client or Connection instance and table names. ```typescript import { Lucia } from "lucia"; import { PlanetScaleAdapter } from "@lucia-auth/adapter-mysql"; import { Client } from "@planetscale/database"; const client = new Client(); const adapter = new PlanetScaleAdapter(client, { user: "user", session: "user_session" }); ``` -------------------------------- ### Configure Lucia with User Attributes Source: https://v3.lucia-auth.com/tutorials/username-and-password/sveltekit Set up the Lucia instance in SvelteKit to include username in user attributes and configure session cookie security for production. ```typescript // src/lib/server/auth.ts import { Lucia } from "lucia"; import { dev } from "$app/environment"; export const lucia = new Lucia(adapter, { sessionCookie: { attributes: { secure: !dev } }, getUserAttributes: (attributes) => { return { // attributes has the type of DatabaseUserAttributes username: attributes.username }; } }); declare module "lucia" { interface Register { Lucia: typeof lucia; DatabaseUserAttributes: DatabaseUserAttributes; } } interface DatabaseUserAttributes { username: string; } ```