Skip to content

Feature - adding better auth for handling authentication and session management (server) #3446

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3a2f035
new commit
PurnenduMIshra129th Apr 11, 2025
6277a88
fixed python workflow
PurnenduMIshra129th Apr 11, 2025
dbacceb
fixed test cases
PurnenduMIshra129th Apr 12, 2025
6238cbe
Merge branch 'develop-postgres' of https://github.com/PalisadoesFound…
PurnenduMIshra129th Apr 12, 2025
107c916
fixing code quality
PurnenduMIshra129th Apr 12, 2025
1f6022d
fixed some type errors
PurnenduMIshra129th Apr 12, 2025
093706f
fixed compose file in docker
PurnenduMIshra129th Apr 12, 2025
12940aa
API_CORS_ORIGIN changed in compose file
PurnenduMIshra129th Apr 12, 2025
0532750
fixed pinio pretty problem
PurnenduMIshra129th Apr 14, 2025
7d74c83
Merge branch 'develop-postgres' of https://github.com/PalisadoesFound…
PurnenduMIshra129th Apr 14, 2025
d1996c1
fixed code quality
PurnenduMIshra129th Apr 14, 2025
b75e854
trying to fix code quality
PurnenduMIshra129th Apr 14, 2025
0e02585
trying to fix code quality
PurnenduMIshra129th Apr 14, 2025
8feec3e
fixed lockfile
PurnenduMIshra129th Apr 14, 2025
3cc8b5a
not completed yet
PurnenduMIshra129th Apr 20, 2025
40f2fe3
fixed all test cases
PurnenduMIshra129th Apr 21, 2025
5bcc22d
fixed all test cases
PurnenduMIshra129th Apr 21, 2025
d8aee8b
Merge branch 'develop-postgres' of https://github.com/PalisadoesFound…
PurnenduMIshra129th Apr 21, 2025
01077f4
fixed test cases
PurnenduMIshra129th Apr 22, 2025
4fb3997
added test cases for createServer.test.ts for betterAuth
PurnenduMIshra129th Apr 23, 2025
9b853c8
repushing code fix postgres connection not changed anything
PurnenduMIshra129th Apr 23, 2025
92050b9
added test cases for auth.ts , db.ts , betterAuthSetUp.ts
PurnenduMIshra129th Apr 24, 2025
05099e1
fixed test cases and added types to auth.spec ,db.spec
PurnenduMIshra129th Apr 26, 2025
3529c04
added mocked database in createServer.ts
PurnenduMIshra129th Apr 26, 2025
4b21bc4
added envConfig instead of process.env
PurnenduMIshra129th Apr 26, 2025
4a058fa
fixed code quality
PurnenduMIshra129th Apr 26, 2025
01fad41
added test host in db.ts
PurnenduMIshra129th Apr 26, 2025
0f01aa6
reverted the db.ts addition of test_host
PurnenduMIshra129th Apr 26, 2025
a1b7af5
changed the createServer to testServer defined in test files which ca…
PurnenduMIshra129th Apr 26, 2025
f94000d
Merge branch 'develop-postgres' into feature/betterAuth4
palisadoes May 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ services:
- API_RATE_LIMIT_REFILL_RATE=${API_RATE_LIMIT_REFILL_RATE:?error}
- CI=${CI:?error}
- NODE_ENV=${NODE_ENV:?error}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:?error}
- API_CORS_ORIGIN =${API_CORS_ORIGIN :?error}
# https://docs.docker.com/reference/compose-file/build/#using-build-and-image
# https://docs.docker.com/reference/compose-file/build/#publishing-built-images
# https://docs.docker.com/reference/compose-file/services/#image
Expand Down
2 changes: 2 additions & 0 deletions docker/compose.deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ services:
- API_RATE_LIMIT_REFILL_RATE=${API_RATE_LIMIT_REFILL_RATE:?error}
- CI=${CI:?error}
- NODE_ENV=${NODE_ENV:?error}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:?error}
- API_CORS_ORIGIN =${API_CORS_ORIGIN :?error}
# https://docs.docker.com/reference/compose-file/build/#using-build-and-image
# https://docs.docker.com/reference/compose-file/build/#publishing-built-images
# https://docs.docker.com/reference/compose-file/services/#image
Expand Down
185 changes: 185 additions & 0 deletions docs/docs/docs/developer-resources/better-auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# Better Auth Integration with Fastify and GraphQL

## Overview
This document explains how **Better Auth** integrates with **Fastify** and **GraphQL** for authentication. It provides details on environment setup, database schema, middleware configuration, and how requests are handled.

---

## 1. Setting Up Environment Variables
Make sure you have the required environment variables in your `.env` file. The `BETTER_AUTH_SECRET` must be set, and its value can be generated from [this link](https://better-auth.vercel.app/docs/installation).

### Required Environment Variables:
```env
BETTER_AUTH_SECRET=<your_generated_secret>
API_POSTGRES_USER=<your_db_user>
API_POSTGRES_PASSWORD=<your_db_password>
API_POSTGRES_HOST=<your_db_host>
API_POSTGRES_PORT=<your_db_port>
API_POSTGRES_DATABASE=<your_db_name>
API_CORS_ORIGIN = <your client URL>
NODE_ENV=<Production or development or test>
```

---

## 2. Connecting to PostgreSQL with Drizzle ORM

We use **Drizzle ORM** to connect to the PostgreSQL database. The connection URL is dynamically constructed from environment variables.

```typescript
import dotenv from "dotenv";
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";

dotenv.config();

const DATABASE_URL = `postgres://${process.env.API_POSTGRES_USER}:${process.env.API_POSTGRES_PASSWORD}@${process.env.API_POSTGRES_HOST}:${process.env.API_POSTGRES_PORT}/${process.env.API_POSTGRES_DATABASE}`;

const client = postgres(DATABASE_URL, {
prepare: false,
// debug: (connection, query, params) => {
// console.log("Running SQL Query:", query);
// console.log("📌 Query Parameters:", params);
// },
});

// Connect Drizzle ORM
export const db = drizzle(client);
```

### Notes:
- **Ensure `.env` variables are properly set** before running the application.
- If you want to **debug SQL queries**, uncomment the `console.log` lines in the `debug` option.

---

## 3. Database Schema & Migrations
The required database tables for **Better Auth** are already created, and migration files are present.

### Important Migrations:
1. **Main Migration**: `20250122092015_sweet_scrambler.sql`
2. **Better Auth Migration**: `20250303173255_cheerful_deadpool.sql`

### To Apply Migrations:
Run the following command to ensure all database changes are applied:
```sh
npm run apply_drizzle_migrations
```
✅ If you have already migrated the **main migration file**, you only need to migrate `20250303173255_cheerful_deadpool.sql`. There is no need to manually create tables.

---

## 4. Authentication Middleware
To integrate **Better Auth** with Fastify, we redirect all `/api/auth/*` requests to `auth.ts`, where authentication logic is handled.

### Updated `createServer` Code:
```typescript
fastify.all("/api/auth/*", async (req, reply) => {
console.log(`✅ Route hit: ${req.method} ${req.url}`);

const headers: Record<string, string> = {};
for (const [key, value] of Object.entries(req.headers)) {
if (value) {
headers[key] = Array.isArray(value) ? value.join(", ") : value;
}
}

const fetchRequest = new Request(
`${req.protocol}://${req.hostname}${req.url}`,
{
method: req.method,
headers,
body:
req.method !== "GET" && req.method !== "HEAD"
? JSON.stringify(req.body)
: undefined,
}
);

// Handle authentication
const response = await auth.handler(fetchRequest);

// Send response back to Fastify
reply.status(response.status);
response.headers.forEach((value, key) => reply.header(key, value));
reply.send(await response.text());
});
```

- This ensures that all authentication-related requests are handled by **Better Auth** before reaching GraphQL.
- It converts Fastify requests into **Fetch API** requests, making them compatible with **Better Auth** handlers.

---

## 5. CORS Configuration
To prevent **CORS errors**, we enable **CORS support** for both **GraphQL and Better Auth** using `fastify-cors`:

```typescript
fastify.register(fastifyCors, {
origin: "http://localhost:4321", // Allow only your frontend origin
credentials: true, // Allow sending cookies and authentication headers
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], // Allowed methods
allowedHeaders: [
"Content-Type",
"Authorization",
"apollo-require-preflight",
],
});
```

- **Origin restriction:** Allows requests only from `http://localhost:4321`.
- **Credentials enabled:** Ensures authentication headers and cookies are passed.
- **Allowed methods:** `GET`, `POST`, `PUT`, `DELETE`, `OPTIONS`.

---

## 6. Better Auth Configuration (`auth.ts`)
The authentication logic is defined inside `/src/lib/auth.ts`. Below is a summary of how **Better Auth** is configured:

```typescript
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
schema: {
user: usersTable,
account: accountTable,
session: sessionTable,
verification: verificationTable,
},
}),
advanced: {
generateId: false,
},
user: {
modelName: "user",
fields: {
email: "emailAddress",
emailVerified: "isEmailAddressVerified",
},
},
session: {
expiresIn: 60 * 60 * 24 * 7, // 7 days
updateAge: 60 * 60 * 24, // 1 day
freshAge: 60 * 5, // 5 minutes
cookieCache: {
enabled: true,
maxAge: 5 * 60,
},
},
emailAndPassword: {
enabled: true,
},
trustedOrigins: ["http://localhost:4321"],
});
```

### Key Features:
- Uses **Drizzle ORM** as a database adapter.
- Supports **email and password authentication**.
- Implements **session management** with refresh-like cookie caching.
- Allows **role-based access** and **trusted origins**.

---

## Conclusion
You have successfully integrated **Better Auth** with Fastify and GraphQL. Ensure the **environment variables**, **migrations**, and **CORS settings** are properly configured. 🚀
15 changes: 15 additions & 0 deletions docs/docs/docs/getting-started/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,22 @@ This environment variable is used to configure the host port to map with the con

- More information can be found at [this](https://docs.docker.com/engine/network/##published-ports) link.

### `API_CORS_ORIGIN`

This environment variable is used to specify the allowed origin(s) for Cross-Origin Resource Sharing (CORS). It defines which domains are permitted to interact with the API by sending requests from a different origin.

- **Usage Example:**
```bash
API_CORS_ORIGIN=http://example.com

### `BETTER_AUTH_SECRET`

This environment variable is used to define the secret key for signing and verifying authentication tokens in the Better Auth system. It is essential for ensuring the security and integrity of user sessions.

- **Usage Example:**
```bash
BETTER_AUTH_SECRET=your_super_secret_key_here
## docker compose
### COMPOSE_FILE
Expand Down
44 changes: 44 additions & 0 deletions drizzle_migrations/20250411200702_natural_silk_fever.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
CREATE TABLE "account" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"account_id" text NOT NULL,
"provider_id" text NOT NULL,
"user_id" uuid NOT NULL,
"access_token" text,
"refresh_token" text,
"id_token" text,
"access_token_expires_at" timestamp,
"refresh_token_expires_at" timestamp,
"scope" text,
"password" text,
"created_at" timestamp NOT NULL,
"updated_at" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE "session" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"expires_at" timestamp NOT NULL,
"token" text NOT NULL,
"created_at" timestamp NOT NULL,
"updated_at" timestamp NOT NULL,
"ip_address" text,
"user_agent" text,
"user_id" uuid NOT NULL,
CONSTRAINT "session_token_unique" UNIQUE("token")
);
--> statement-breakpoint
CREATE TABLE "verification" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"identifier" text NOT NULL,
"value" text NOT NULL,
"expires_at" timestamp NOT NULL,
"created_at" timestamp,
"updated_at" timestamp
);
--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "is_email_address_verified" SET DEFAULT false;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "is_email_address_verified" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "password_hash" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "role" SET DEFAULT 'regular';--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "role" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "account" ADD CONSTRAINT "account_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "session" ADD CONSTRAINT "session_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
Loading