From 8c9a43796eb90c31f56377d5cf94614890baea5c Mon Sep 17 00:00:00 2001 From: yukikwi Date: Sat, 12 Oct 2024 22:19:40 +0700 Subject: [PATCH] feat: better auth and cors integrations --- .env.dist | 4 +- README.md | 2 + bun.lockb | Bin 29744 -> 127902 bytes .../0001_thankful_mathemanic.sql | 49 +++ database_migrations/meta/0001_snapshot.json | 286 ++++++++++++++++++ database_migrations/meta/_journal.json | 7 + drizzle.config.ts | 5 +- package.json | 5 +- src/auth/models/better_auth.ts | 38 +++ src/auth/routers.ts | 8 + src/auth/views.ts | 24 ++ src/config.ts | 4 + src/lib/auth.ts | 20 ++ src/server.ts | 10 +- 14 files changed, 458 insertions(+), 4 deletions(-) create mode 100644 database_migrations/0001_thankful_mathemanic.sql create mode 100644 database_migrations/meta/0001_snapshot.json create mode 100644 src/auth/models/better_auth.ts create mode 100644 src/auth/routers.ts create mode 100644 src/auth/views.ts create mode 100644 src/lib/auth.ts diff --git a/.env.dist b/.env.dist index 9c4f729..056a6d9 100644 --- a/.env.dist +++ b/.env.dist @@ -3,4 +3,6 @@ DB_HOST="localhost" DB_PORT="5432" DB_USER="postgres" DB_PASSWORD="xxxxxx" -DB_NAME="example" \ No newline at end of file +DB_NAME="example" +FRONTEND_URL="http://localhost:3001" +BETTER_AUTH_SECRET=RANDOM_STRING (check https://www.better-auth.com/docs/installation) diff --git a/README.md b/README.md index c0df61f..06ff976 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ - [x] App based folder structure - [x] Postgres database support (drizzle) - [x] Serve static files +- [x] Better auth integration +- [x] CORS support ## Getting Started To get started with this template, simply paste this command into your terminal: diff --git a/bun.lockb b/bun.lockb index 68adb4ab362e3b025e3ee8355db387e67f2b669a..58c70456db6ad9e8a408966af808bef4d29ef6ea 100755 GIT binary patch literal 127902 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

sfz6899Mfgz?n}-NLN@4S8gmw>N%l{R^Te9FE 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 EKk#t=w*UYD delta 5862 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 HKK statement-breakpoint +CREATE TABLE IF NOT EXISTS "session" ( + "id" text PRIMARY KEY NOT NULL, + "expiresAt" timestamp NOT NULL, + "ipAddress" text, + "userAgent" text, + "userId" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "user" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "email" text NOT NULL, + "emailVerified" boolean NOT NULL, + "image" text, + "createdAt" timestamp NOT NULL, + "updatedAt" timestamp NOT NULL, + CONSTRAINT "user_email_unique" UNIQUE("email") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "verification" ( + "id" text PRIMARY KEY NOT NULL, + "identifier" text NOT NULL, + "value" text NOT NULL, + "expiresAt" timestamp NOT NULL +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "account" ADD CONSTRAINT "account_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "session" ADD CONSTRAINT "session_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/database_migrations/meta/0001_snapshot.json b/database_migrations/meta/0001_snapshot.json new file mode 100644 index 0000000..e218592 --- /dev/null +++ b/database_migrations/meta/0001_snapshot.json @@ -0,0 +1,286 @@ +{ + "id": "56ce94aa-a168-4104-ba96-f7e2973fad5c", + "prevId": "8164177c-dd44-4165-b734-fc0acaa9171b", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.animals": { + "name": "animals", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "science_name": { + "name": "science_name", + "type": "varchar(512)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "name_idx": { + "name": "name_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "accountId": { + "name": "accountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerId": { + "name": "providerId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "accessToken": { + "name": "accessToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "idToken": { + "name": "idToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userAgent": { + "name": "userAgent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + } + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/database_migrations/meta/_journal.json b/database_migrations/meta/_journal.json index 754aad8..3f21571 100644 --- a/database_migrations/meta/_journal.json +++ b/database_migrations/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1725031182851, "tag": "0000_mysterious_magma", "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1728741980064, + "tag": "0001_thankful_mathemanic", + "breakpoints": true } ] } \ No newline at end of file diff --git a/drizzle.config.ts b/drizzle.config.ts index dc4db02..480b749 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -1,7 +1,10 @@ import { defineConfig } from 'drizzle-kit'; export default defineConfig({ - schema: './src/**/models.ts', + schema: [ + './src/**/models.ts', + './src/**/models/*.ts' + ], out: './database_migrations', dialect: 'postgresql', dbCredentials: { diff --git a/package.json b/package.json index 5660d0a..e0ac60b 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,15 @@ "dev": "bun run --watch src/server.ts", "build": "bun build --minify --target bun --outdir dist src/index.ts", "compile": "bun build --compile --minify --target bun --outfile server src/index.ts", + "better-auth_generate": "npx better-auth generate --output=src/auth/models/better_auth.ts", "makemigrations": "npx drizzle-kit generate", "migrate": "npx drizzle-kit migrate" }, "dependencies": { + "@elysiajs/cors": "^1.1.1", "@elysiajs/static": "^1.1.1", - "@elysiajs/swagger": "^1.1.1", + "@elysiajs/swagger": "^1.1.5", + "better-auth": "^0.4.2", "drizzle-orm": "^0.33.0", "elysia": "latest", "postgres": "^3.4.4" diff --git a/src/auth/models/better_auth.ts b/src/auth/models/better_auth.ts new file mode 100644 index 0000000..2dcb966 --- /dev/null +++ b/src/auth/models/better_auth.ts @@ -0,0 +1,38 @@ +import { pgTable, text, integer, timestamp, boolean } from "drizzle-orm/pg-core"; + +export const user = pgTable("user", { + id: text("id").primaryKey(), + name: text('name').notNull(), + email: text('email').notNull().unique(), + emailVerified: boolean('emailVerified').notNull(), + image: text('image'), + createdAt: timestamp('createdAt').notNull(), + updatedAt: timestamp('updatedAt').notNull() + }); + +export const session = pgTable("session", { + id: text("id").primaryKey(), + expiresAt: timestamp('expiresAt').notNull(), + ipAddress: text('ipAddress'), + userAgent: text('userAgent'), + userId: text('userId').notNull().references(()=> user.id) + }); + +export const account = pgTable("account", { + id: text("id").primaryKey(), + accountId: text('accountId').notNull(), + providerId: text('providerId').notNull(), + userId: text('userId').notNull().references(()=> user.id), + accessToken: text('accessToken'), + refreshToken: text('refreshToken'), + idToken: text('idToken'), + expiresAt: timestamp('expiresAt'), + password: text('password') + }); + +export const verification = pgTable("verification", { + id: text("id").primaryKey(), + identifier: text('identifier').notNull(), + value: text('value').notNull(), + expiresAt: timestamp('expiresAt').notNull() + }); diff --git a/src/auth/routers.ts b/src/auth/routers.ts new file mode 100644 index 0000000..740fc8c --- /dev/null +++ b/src/auth/routers.ts @@ -0,0 +1,8 @@ +import Elysia, { t } from "elysia" +import views from "./views" + +const appPrefix = "/api/auth" +const app = new Elysia({ prefix: appPrefix }) + .all("/*", views.betterAuthView) + +export default app \ No newline at end of file diff --git a/src/auth/views.ts b/src/auth/views.ts new file mode 100644 index 0000000..33af6bc --- /dev/null +++ b/src/auth/views.ts @@ -0,0 +1,24 @@ +import { Context } from "elysia" +import { auth } from "../lib/auth"; + +const betterAuthView = (context: Context) => { + const BETTER_AUTH_ACCEPT_METHODS = ["POST", "GET"] + // validate request method + if(BETTER_AUTH_ACCEPT_METHODS.includes(context.request.method)) { + try { + console.log(context.request.url) + return auth.handler(context.request); + } + catch(error){ + console.log(error) + } + } + else { + context.error(405) + } +} + +// export application views +export default { + betterAuthView +} \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index 92b9747..616574d 100644 --- a/src/config.ts +++ b/src/config.ts @@ -9,6 +9,10 @@ export const DB_PORT = parseInt(process.env.DB_PORT || "5432") export const DB_USER = process.env.DB_USER export const DB_PASSWORD = process.env.DB_PASSWORD export const DB_NAME = process.env.DB_NAME +export const DB_PROVIDER = "pg" + +// CORS domain +export const FRONTEND_URL = process.env.FRONTEND_URL || false // Swagger configuration export const SWAGGER_PATH = "/documents" \ No newline at end of file diff --git a/src/lib/auth.ts b/src/lib/auth.ts new file mode 100644 index 0000000..8500fb2 --- /dev/null +++ b/src/lib/auth.ts @@ -0,0 +1,20 @@ +import { betterAuth } from "better-auth"; +import { drizzleAdapter } from "better-auth/adapters/drizzle"; +import { db } from "../core/database"; // your drizzle instance +import { DB_PROVIDER } from "../config"; +import { account, session, user, verification } from "../auth/models/better_auth"; + +export const auth = betterAuth({ + database: drizzleAdapter(db, { + provider: DB_PROVIDER, + schema: { + user: user, + session: session, + account: account, + verification: verification + } + }), + emailAndPassword: { + enabled: true + }, +}); \ No newline at end of file diff --git a/src/server.ts b/src/server.ts index 6b338b0..ac23542 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,8 +1,10 @@ import { Elysia } from "elysia"; import staticPlugin from "@elysiajs/static"; import { swagger } from '@elysiajs/swagger' -import { APP_PORT, SWAGGER_PATH } from "./config"; +import { APP_PORT, FRONTEND_URL, SWAGGER_PATH } from "./config"; import exampleApp from "./example_app/routers"; +import cors from "@elysiajs/cors"; +import authApp from "./auth/routers"; const app = new Elysia() // static plugin @@ -12,7 +14,13 @@ const app = new Elysia() .use(swagger({ path: SWAGGER_PATH })) + // cors + .use(cors({ + origin: FRONTEND_URL + })) + // load apps .use(exampleApp) + .use(authApp) .listen(APP_PORT); console.log(