Skip to content
This repository was archived by the owner on Oct 22, 2025. It is now read-only.

Commit 680ca62

Browse files
committed
chore(example): add better-auth-external-sql example (#1028)
1 parent 30a7363 commit 680ca62

File tree

24 files changed

+224
-66
lines changed

24 files changed

+224
-66
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Dependencies
2+
node_modules
3+
.pnpm-debug.log*
4+
5+
# Build outputs
6+
dist
7+
.turbo
8+
9+
# Environment variables
10+
.env
11+
.env.local
12+
.env.production.local
13+
.env.development.local
14+
15+
# Database
16+
*.sqlite
17+
*.db
18+
19+
# IDE
20+
.vscode
21+
.idea
22+
23+
# OS
24+
.DS_Store
25+
Thumbs.db
26+
27+
# Logs
28+
*.log
29+
npm-debug.log*
30+
yarn-debug.log*
31+
yarn-error.log*

examples/better-auth/README.md renamed to examples/better-auth-external-db/README.md

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Better Auth Integration for RivetKit
1+
# Better Auth with External Database for RivetKit
22

3-
Example project demonstrating authentication integration with [RivetKit](https://rivetkit.org) using Better Auth.
3+
Example project demonstrating authentication integration with [RivetKit](https://rivetkit.org) using Better Auth and SQLite database.
44

55
[Learn More →](https://github.com/rivet-gg/rivetkit)
66

@@ -17,10 +17,20 @@ Example project demonstrating authentication integration with [RivetKit](https:/
1717

1818
```sh
1919
git clone https://github.com/rivet-gg/rivetkit
20-
cd rivetkit/examples/better-auth
20+
cd rivetkit/examples/better-auth-external-db
2121
npm install
2222
```
2323

24+
### Database Setup
25+
26+
Initialize the SQLite database with Better Auth tables:
27+
28+
```sh
29+
npm run db:setup
30+
```
31+
32+
This will create the `auth.sqlite` database file with the required tables for user authentication.
33+
2434
### Development
2535

2636
```sh
@@ -34,21 +44,26 @@ Open your browser to `http://localhost:5173` to see the frontend and the backend
3444
- **Authentication**: Email/password authentication using Better Auth
3545
- **Protected Actors**: RivetKit actors with authentication via `onAuth` hook
3646
- **Real-time Chat**: Authenticated chat room with real-time messaging
37-
- **SQLite Database**: Persistent user data and session storage
47+
- **External Database**: Shows how to configure Better Auth with external database (SQLite example)
3848

3949
## How It Works
4050

41-
1. **Better Auth Setup**: Configured with SQLite adapter for user storage
51+
1. **Better Auth Setup**: Configured with SQLite database for persistent user storage
4252
2. **Protected Actor**: The `chatRoom` actor uses the `onAuth` hook to verify user sessions
4353
3. **Frontend Integration**: React components handle authentication flow and chat interface
4454
4. **Session Management**: Better Auth handles session creation, validation, and cleanup
4555

56+
## Database Commands
57+
58+
- `npm run db:setup` - Initialize SQLite database with Better Auth tables
59+
4660
## Key Files
4761

48-
- `src/backend/auth.ts` - Better Auth configuration with SQLite
62+
- `src/backend/auth.ts` - Better Auth configuration with SQLite database
4963
- `src/backend/registry.ts` - RivetKit actor with authentication
5064
- `src/frontend/components/AuthForm.tsx` - Login/signup form
5165
- `src/frontend/components/ChatRoom.tsx` - Authenticated chat interface
66+
- `auth.sqlite` - SQLite database file (auto-created)
5267

5368
## License
5469

examples/better-auth/package.json renamed to examples/better-auth-external-db/package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "example-better-auth",
2+
"name": "example-better-auth-external-db",
33
"version": "0.9.0-rc.1",
44
"private": true,
55
"type": "module",
@@ -9,23 +9,26 @@
99
"dev:frontend": "vite",
1010
"build": "vite build",
1111
"check-types": "tsc --noEmit",
12-
"test": "vitest run"
12+
"test": "vitest run",
13+
"db:setup": "tsx scripts/setup-db.ts"
1314
},
1415
"devDependencies": {
16+
"@rivetkit/actor": "workspace:*",
1517
"@types/node": "^22.13.9",
1618
"@types/react": "^18.2.0",
1719
"@types/react-dom": "^18.2.0",
1820
"@vitejs/plugin-react": "^4.2.0",
1921
"concurrently": "^8.2.2",
20-
"@rivetkit/actor": "workspace:*",
2122
"tsx": "^3.12.7",
2223
"typescript": "^5.5.2",
2324
"vite": "^5.0.0",
2425
"vitest": "^3.1.1"
2526
},
2627
"dependencies": {
2728
"@rivetkit/react": "workspace:*",
29+
"@types/better-sqlite3": "^7.6.13",
2830
"better-auth": "^1.0.1",
31+
"better-sqlite3": "^11.10.0",
2932
"hono": "^4.7.0",
3033
"react": "^18.2.0",
3134
"react-dom": "^18.2.0"
File renamed without changes.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import Database from "better-sqlite3";
2+
3+
// Create SQLite database and tables for Better Auth
4+
const db = new Database("/tmp/auth.sqlite");
5+
6+
// Create user table
7+
db.exec(`
8+
CREATE TABLE IF NOT EXISTS user (
9+
id TEXT PRIMARY KEY,
10+
email TEXT UNIQUE NOT NULL,
11+
emailVerified BOOLEAN NOT NULL DEFAULT FALSE,
12+
name TEXT NOT NULL,
13+
createdAt INTEGER NOT NULL,
14+
updatedAt INTEGER NOT NULL
15+
);
16+
`);
17+
18+
// Create session table
19+
db.exec(`
20+
CREATE TABLE IF NOT EXISTS session (
21+
id TEXT PRIMARY KEY,
22+
userId TEXT NOT NULL,
23+
expiresAt INTEGER NOT NULL,
24+
token TEXT UNIQUE NOT NULL,
25+
createdAt INTEGER NOT NULL,
26+
updatedAt INTEGER NOT NULL,
27+
ipAddress TEXT,
28+
userAgent TEXT,
29+
FOREIGN KEY (userId) REFERENCES user(id) ON DELETE CASCADE
30+
);
31+
`);
32+
33+
// Create account table
34+
db.exec(`
35+
CREATE TABLE IF NOT EXISTS account (
36+
id TEXT PRIMARY KEY,
37+
userId TEXT NOT NULL,
38+
accountId TEXT NOT NULL,
39+
providerId TEXT NOT NULL,
40+
accessToken TEXT,
41+
refreshToken TEXT,
42+
idToken TEXT,
43+
accessTokenExpiresAt INTEGER,
44+
refreshTokenExpiresAt INTEGER,
45+
scope TEXT,
46+
password TEXT,
47+
createdAt INTEGER NOT NULL,
48+
updatedAt INTEGER NOT NULL,
49+
FOREIGN KEY (userId) REFERENCES user(id) ON DELETE CASCADE
50+
);
51+
`);
52+
53+
// Create verification table
54+
db.exec(`
55+
CREATE TABLE IF NOT EXISTS verification (
56+
id TEXT PRIMARY KEY,
57+
identifier TEXT NOT NULL,
58+
value TEXT NOT NULL,
59+
expiresAt INTEGER NOT NULL,
60+
createdAt INTEGER NOT NULL,
61+
updatedAt INTEGER NOT NULL
62+
);
63+
`);
64+
65+
console.log("Database tables created successfully!");
66+
db.close();
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { betterAuth } from "better-auth";
2+
import Database from "better-sqlite3";
3+
4+
export const auth = betterAuth({
5+
database: new Database("/tmp/auth.sqlite"),
6+
trustedOrigins: ["http://localhost:5173"],
7+
emailAndPassword: {
8+
enabled: true,
9+
},
10+
});

examples/better-auth/src/backend/registry.ts renamed to examples/better-auth-external-db/src/backend/registry.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { actor, OnAuthOptions, setup, UserError } from "@rivetkit/actor";
1+
import { actor, setup, type OnAuthOptions } from "@rivetkit/actor";
2+
import { Unauthorized } from "@rivetkit/actor/errors";
23
import { auth } from "./auth";
34

45
interface State {
@@ -13,17 +14,25 @@ interface Message {
1314
timestamp: number;
1415
}
1516

17+
18+
19+
20+
21+
22+
23+
24+
25+
1626
export const chatRoom = actor({
27+
// onAuth runs on the server & before connecting to the actor
1728
onAuth: async (c: OnAuthOptions) => {
29+
// ✨ NEW ✨ Access Better Auth session
1830
const authResult = await auth.api.getSession({
1931
headers: c.req.headers,
2032
});
21-
console.log("auth result", authResult);
22-
23-
if (!authResult?.session || !authResult?.user) {
24-
throw new UserError("Unauthorized");
25-
}
33+
if (!authResult) throw new Unauthorized();
2634

35+
// Passes auth data to the actor (c.conn.auth)
2736
return {
2837
user: authResult.user,
2938
session: authResult.session,
@@ -34,10 +43,11 @@ export const chatRoom = actor({
3443
} as State,
3544
actions: {
3645
sendMessage: (c, message: string) => {
46+
// ✨ NEW ✨ — Access Better Auth with c.conn.auth
3747
const newMessage = {
3848
id: crypto.randomUUID(),
39-
userId: "TODO",
40-
username: c.conn.auth.user.email || "Unknown",
49+
userId: c.conn.auth.user.id,
50+
username: c.conn.auth.user.name,
4151
message,
4252
timestamp: Date.now(),
4353
};
@@ -53,6 +63,17 @@ export const chatRoom = actor({
5363
},
5464
});
5565

66+
67+
68+
69+
70+
71+
72+
73+
74+
75+
76+
5677
export const registry = setup({
5778
use: { chatRoom },
5879
});

examples/better-auth/src/backend/server.ts renamed to examples/better-auth-external-db/src/backend/server.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import { registry } from "./registry";
22
import { auth } from "./auth";
33
import { Hono } from "hono";
44
import { cors } from "hono/cors";
5+
import { ALLOWED_PUBLIC_HEADERS } from "@rivetkit/actor";
56

67
// Start RivetKit
7-
const { client, hono, serve } = registry.createServer();
8+
const { serve } = registry.createServer();
89

910
// Setup router
1011
const app = new Hono();
@@ -13,7 +14,8 @@ app.use(
1314
"*",
1415
cors({
1516
origin: ["http://localhost:5173"],
16-
allowHeaders: ["Content-Type", "Authorization"],
17+
// Need to allow custom headers used in RivetKit
18+
allowHeaders: ["Authorization", ...ALLOWED_PUBLIC_HEADERS],
1719
allowMethods: ["POST", "GET", "OPTIONS"],
1820
exposeHeaders: ["Content-Length"],
1921
maxAge: 600,

0 commit comments

Comments
 (0)