Lucia Authentication (#8)
* initial lucia installation * added prismAdapter for lucia * fixed adapter * main lucia set * moved into correct folder * fixed * removed npm lock * removed supabase(i swear) * Lucia register done * lucia login done * removed * fixed issues with uuid * fixed all commented issues * fixed event param * Update +page.server.ts Signed-off-by: DanMihailescu <as42554525@yahoo.ca> * Update lucia.ts Signed-off-by: DanMihailescu <as42554525@yahoo.ca> --------- Signed-off-by: DanMihailescu <as42554525@yahoo.ca> Co-authored-by: Dan Mihailescu <dan.mihailescu5@gmail.com>
This commit is contained in:
parent
242ec113f6
commit
992eb07f5c
11 changed files with 108 additions and 72 deletions
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
|
@ -52,6 +52,7 @@
|
||||||
"vitest": "^2.0.4"
|
"vitest": "^2.0.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@lucia-auth/adapter-prisma": "^4.0.1",
|
||||||
"@pothos/core": "^4.3.0",
|
"@pothos/core": "^4.3.0",
|
||||||
"@pothos/plugin-prisma": "^4.4.0",
|
"@pothos/plugin-prisma": "^4.4.0",
|
||||||
"@prisma/client": "6.0.1",
|
"@prisma/client": "6.0.1",
|
||||||
|
|
@ -59,6 +60,8 @@
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"graphql": "^16.9.0",
|
"graphql": "^16.9.0",
|
||||||
"graphql-yoga": "^5.10.4",
|
"graphql-yoga": "^5.10.4",
|
||||||
|
"lucia": "^3.2.2",
|
||||||
|
"oslo": "^1.2.1",
|
||||||
"pino": "^9.5.0",
|
"pino": "^9.5.0",
|
||||||
"pino-pretty": "^13.0.0",
|
"pino-pretty": "^13.0.0",
|
||||||
"tailwind-merge": "^2.5.5",
|
"tailwind-merge": "^2.5.5",
|
||||||
|
|
|
||||||
BIN
prisma/dev.db
BIN
prisma/dev.db
Binary file not shown.
|
|
@ -1,19 +0,0 @@
|
||||||
-- CreateTable
|
|
||||||
CREATE TABLE "User" (
|
|
||||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
||||||
"email" TEXT NOT NULL,
|
|
||||||
"name" TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateTable
|
|
||||||
CREATE TABLE "Post" (
|
|
||||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
||||||
"title" TEXT NOT NULL,
|
|
||||||
"content" TEXT,
|
|
||||||
"published" BOOLEAN NOT NULL DEFAULT false,
|
|
||||||
"authorId" INTEGER NOT NULL,
|
|
||||||
CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
Warnings:
|
|
||||||
|
|
||||||
- Made the column `content` on table `Post` required. This step will fail if there are existing NULL values in that column.
|
|
||||||
- Made the column `name` on table `User` required. This step will fail if there are existing NULL values in that column.
|
|
||||||
|
|
||||||
*/
|
|
||||||
-- RedefineTables
|
|
||||||
PRAGMA defer_foreign_keys=ON;
|
|
||||||
PRAGMA foreign_keys=OFF;
|
|
||||||
CREATE TABLE "new_Post" (
|
|
||||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
||||||
"title" TEXT NOT NULL,
|
|
||||||
"content" TEXT NOT NULL,
|
|
||||||
"published" BOOLEAN DEFAULT false,
|
|
||||||
"authorId" INTEGER NOT NULL,
|
|
||||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
INSERT INTO "new_Post" ("authorId", "content", "id", "published", "title") SELECT "authorId", "content", "id", "published", "title" FROM "Post";
|
|
||||||
DROP TABLE "Post";
|
|
||||||
ALTER TABLE "new_Post" RENAME TO "Post";
|
|
||||||
CREATE TABLE "new_User" (
|
|
||||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
||||||
"email" TEXT,
|
|
||||||
"name" TEXT NOT NULL,
|
|
||||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
||||||
);
|
|
||||||
INSERT INTO "new_User" ("email", "id", "name") SELECT "email", "id", "name" FROM "User";
|
|
||||||
DROP TABLE "User";
|
|
||||||
ALTER TABLE "new_User" RENAME TO "User";
|
|
||||||
CREATE UNIQUE INDEX "User_id_key" ON "User"("id");
|
|
||||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
|
||||||
PRAGMA foreign_keys=ON;
|
|
||||||
PRAGMA defer_foreign_keys=OFF;
|
|
||||||
24
prisma/migrations/20241215222709_removed_issue/migration.sql
Normal file
24
prisma/migrations/20241215222709_removed_issue/migration.sql
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- The primary key for the `Post` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- RedefineTables
|
||||||
|
PRAGMA defer_foreign_keys=ON;
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
CREATE TABLE "new_Post" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"title" TEXT NOT NULL,
|
||||||
|
"content" TEXT NOT NULL,
|
||||||
|
"published" BOOLEAN DEFAULT false,
|
||||||
|
"authorId" TEXT NOT NULL,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO "new_Post" ("authorId", "content", "createdAt", "id", "published", "title", "updatedAt") SELECT "authorId", "content", "createdAt", "id", "published", "title", "updatedAt" FROM "Post";
|
||||||
|
DROP TABLE "Post";
|
||||||
|
ALTER TABLE "new_Post" RENAME TO "Post";
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
|
PRAGMA defer_foreign_keys=OFF;
|
||||||
|
|
@ -15,21 +15,34 @@ datasource db {
|
||||||
}
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id Int @id @default(autoincrement()) @unique
|
id String @id @default(uuid())
|
||||||
email String? @unique
|
email String? @unique
|
||||||
name String
|
name String
|
||||||
|
password String
|
||||||
posts Post[]
|
posts Post[]
|
||||||
|
sessions Session[]
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Session {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
expiresAt DateTime
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
userId String
|
||||||
|
user User @relation(references: [id], fields: [userId])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
model Post {
|
model Post {
|
||||||
id Int @id @default(autoincrement())
|
id String @id @default(uuid())
|
||||||
title String
|
title String
|
||||||
content String
|
content String
|
||||||
published Boolean? @default(false)
|
published Boolean? @default(false)
|
||||||
author User @relation(fields: [authorId], references: [id])
|
author User @relation(references: [id], fields: [authorId])
|
||||||
authorId Int
|
authorId String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
}
|
}
|
||||||
6
src/app.d.ts
vendored
6
src/app.d.ts
vendored
|
|
@ -2,8 +2,12 @@
|
||||||
// for information about these interfaces
|
// for information about these interfaces
|
||||||
declare global {
|
declare global {
|
||||||
namespace App {
|
namespace App {
|
||||||
|
|
||||||
// interface Error {}
|
// interface Error {}
|
||||||
// interface Locals {}
|
interface Locals {
|
||||||
|
user: import("lucia").User | null;
|
||||||
|
session: import('lucia').Session | null;
|
||||||
|
}
|
||||||
// interface PageData {}
|
// interface PageData {}
|
||||||
// interface PageState {}
|
// interface PageState {}
|
||||||
// interface Platform {}
|
// interface Platform {}
|
||||||
|
|
|
||||||
31
src/lib/server/lucia.ts
Normal file
31
src/lib/server/lucia.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { Lucia } from 'lucia';
|
||||||
|
import { PrismaAdapter } from '@lucia-auth/adapter-prisma';
|
||||||
|
import { prisma } from '$lib/server/prisma';
|
||||||
|
|
||||||
|
const adapter = new PrismaAdapter(prisma.session, prisma.user);
|
||||||
|
// expect error (see next section)
|
||||||
|
export const auth = new Lucia(adapter, {
|
||||||
|
sessionCookie: {
|
||||||
|
attributes: {
|
||||||
|
secure: process.env.NODE_ENV === 'production'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getUserAttributes: (attributes) => {
|
||||||
|
return {
|
||||||
|
email: attributes.email
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
declare module 'lucia' {
|
||||||
|
interface Register {
|
||||||
|
Lucia: typeof Lucia;
|
||||||
|
DatabaseUserAttributes: DatabaseUserAttributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DatabaseUserAttributes {
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Auth = typeof auth;
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
import { prisma } from '$lib/server/prisma';
|
import { prisma } from '$lib/server/prisma';
|
||||||
|
|
||||||
export async function load(event) {
|
export async function load(event) {
|
||||||
const userId = event.cookies.get('user');
|
const userId = event.cookies.get('user');
|
||||||
if (!userId && isNaN(Number(userId))) {
|
if (!userId) {
|
||||||
return {
|
return {
|
||||||
authenticated: false
|
authenticated: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const user = await prisma.user.findUnique({
|
const user = await prisma.user.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id: Number(userId)
|
id: userId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import { logger } from '$lib/server/logger';
|
import { logger } from '$lib/server/logger';
|
||||||
import { prisma } from '$lib/server/prisma';
|
import { prisma } from '$lib/server/prisma';
|
||||||
import { error, redirect, type Actions } from '@sveltejs/kit';
|
import { error, redirect, type Actions } from '@sveltejs/kit';
|
||||||
|
import { Argon2id } from 'oslo/password';
|
||||||
|
import { auth } from '$lib/server/lucia.js';
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
login: async (event) => {
|
login: async (event) => {
|
||||||
|
|
@ -17,27 +19,43 @@ export const actions = {
|
||||||
logger.error('User not found! ${user}');
|
logger.error('User not found! ${user}');
|
||||||
return error(401);
|
return error(401);
|
||||||
}
|
}
|
||||||
event.cookies.set('user', String(user.id), {
|
const password = form.get('password') as string;
|
||||||
|
if (!password) {
|
||||||
|
return error(401, 'Password is required');
|
||||||
|
}
|
||||||
|
const validPassword = await new Argon2id().verify(user.password, password);
|
||||||
|
if (!validPassword) {
|
||||||
|
return error(400, 'Password is incorrect!');
|
||||||
|
}
|
||||||
|
const session = await auth.createSession(user.id, []);
|
||||||
|
const sessionCookie = auth.createSessionCookie(session.id);
|
||||||
|
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||||
path: '/',
|
path: '/',
|
||||||
maxAge: 120
|
maxAge: 120
|
||||||
});
|
});
|
||||||
redirect(302, '/');
|
redirect(302, '/');
|
||||||
},
|
},
|
||||||
|
|
||||||
register: async (event) => {
|
register: async (event) => {
|
||||||
const form = await event.request.formData();
|
const form = await event.request.formData();
|
||||||
if (!form.has('email') || !form.has('name')) {
|
if (!form.has('email') || !form.has('name') || !form.has('password')) {
|
||||||
return error(400);
|
return error(400);
|
||||||
}
|
}
|
||||||
|
const password = form.get('password') as string;
|
||||||
|
const hashedPassword = await new Argon2id().hash(password);
|
||||||
const user = await prisma.user.create({
|
const user = await prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
email: form.get('email') as string,
|
email: form.get('email') as string,
|
||||||
name: form.get('name') as string
|
name: form.get('name') as string,
|
||||||
|
password: hashedPassword
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const session = await auth.createSession(user.id.toString(), {});
|
||||||
|
const sessionCookie = auth.createSessionCookie(session.id);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return error(500);
|
return error(500);
|
||||||
}
|
}
|
||||||
event.cookies.set('user', String(user.id), {
|
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||||
path: '/',
|
path: '/',
|
||||||
maxAge: 120
|
maxAge: 120
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue