Upgrade password-based auth to v3
Update database
You can continue using the keys table but we recommend either creating a dedicated table for storing passwords or storing passwords in the user table, as shown in the database migration guides.
Create users
Lucia provides LegacyScrypt
for hashing and comparing passwords using the algorithm used in v1 and v2. For future projects, we recommend using Argon2id
or Scrypt
provided by Oslo.
import { generateId, LegacyScrypt } from "lucia";
// v2 IDs have a length of 15
const userId = generateId(15);
await db.beginTransaction();
// create user manually
await db.table("user").insert({
id: userId,
username
});
// store oauth account
await db.table("password").insert({
hashed_password: await new LegacyScrypt().hash(password),
user_id: userId
});
await db.commit();
// simplified `createSession()` - second param for session attributes
const session = await lucia.createSession(userId, {});
// `createSessionCookie()` now takes a session ID instead of the entire session object
const sessionCookie = lucia.createSessionCookie(session.id);
// set session cookie as usual (using `Response` as example)
return new Response(null, {
status: 302,
headers: {
Location: "/",
"Set-Cookie": sessionCookie.serialize()
}
});
Authenticate users
Use verify()
to validate passwords.
import { LegacyScrypt } from "lucia";
// using consecutive queries to simplify example but you can use joins
const user = await db.table("user").where("username", "=", username).get();
if (!user) {
return new Response("Invalid username or password", {
status: 400
});
}
const credentials = await db.table("password").where("user_id", "=", user.id).get();
if (!user) {
return new Response("Invalid username or password", {
status: 400
});
}
const validPassword = await new LegacyScrypt().verify(credentials.hashed_password, password);
if (!validPassword) {
return new Response("Invalid username or password", {
status: 400
});
}
// create sessions...