Skip to content

Commit 34341cb

Browse files
committed
chore: sep out auth pkg and email templates
1 parent b244b90 commit 34341cb

23 files changed

Lines changed: 4875 additions & 3253 deletions

File tree

.npmrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
public-hoist-pattern[]=*better-auth*
2+
public-hoist-pattern[]=*@better-auth*

apps/api/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818
"dependencies": {
1919
"@fastify/cors": "^10.0.1",
2020
"@paralleldrive/cuid2": "^2.2.2",
21+
"@refref/auth": "workspace:*",
2122
"@refref/coredb": "workspace:*",
2223
"@refref/id": "workspace:*",
2324
"@refref/types": "workspace:*",
2425
"@refref/utils": "workspace:*",
2526
"@tsndr/cloudflare-worker-jwt": "^3.2.0",
26-
"better-auth": "^1.3.32",
2727
"dotenv": "^17.2.3",
28-
"drizzle-orm": "^0.33.0",
28+
"drizzle-orm": "^0.44.7",
2929
"fastify": "^5.2.0",
3030
"fastify-plugin": "^5.0.1",
3131
"jose": "^5.9.6",

apps/api/src/plugins/better-auth.ts

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
22
import fp from "fastify-plugin";
3-
import { betterAuth } from "better-auth";
4-
import { drizzleAdapter } from "better-auth/adapters/drizzle";
5-
import { apiKey } from "better-auth/plugins";
6-
import { schema } from "@refref/coredb";
7-
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
3+
import { getAuth } from "@refref/auth";
4+
import { schema, type DBType } from "@refref/coredb";
85

96
declare module "fastify" {
107
interface FastifyRequest {
@@ -26,17 +23,16 @@ declare module "fastify" {
2623
* Better Auth API Key verification plugin for Fastify
2724
* Uses Better Auth's built-in verifyApiKey function with rate limiting and hashing
2825
*/
29-
const betterAuthPlugin = fp(async (fastify: FastifyInstance, opts: { db: PostgresJsDatabase<typeof schema> }) => {
30-
// Create Better Auth instance with the provided database connection
31-
const auth = betterAuth({
32-
database: drizzleAdapter(opts.db, {
33-
provider: "pg",
34-
schema: {
35-
...schema,
36-
},
37-
}),
38-
plugins: [apiKey()],
39-
secret: process.env.BETTER_AUTH_SECRET || "secret-for-development-only",
26+
const betterAuthPlugin = fp(async (fastify: FastifyInstance, opts: { db: DBType }) => {
27+
// Create Better Auth instance using shared @refref/auth package
28+
const auth = getAuth({
29+
baseURL: process.env.APP_URL || "http://localhost:4000",
30+
resendApiKey: process.env.RESEND_API_KEY || "debug_key",
31+
db: opts.db,
32+
schema,
33+
enabledSocialAuth: [],
34+
enablePasswordAuth: false,
35+
enableMagicLinkAuth: false,
4036
});
4137

4238
if (!fastify.hasRequestDecorator("apiKey")) {

apps/refer/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"@refref/utils": "workspace:*",
2424
"@refref/widget": "workspace:*",
2525
"dotenv": "^17.2.3",
26-
"drizzle-orm": "^0.33.0",
26+
"drizzle-orm": "^0.44.7",
2727
"fastify": "^5.2.0",
2828
"postgres": "^3.4.5"
2929
},

apps/webapp/package.json

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,11 @@
5959
"@radix-ui/react-toggle": "^1.1.2",
6060
"@radix-ui/react-toggle-group": "^1.1.2",
6161
"@radix-ui/react-tooltip": "^1.1.8",
62+
"@refref/auth": "workspace:*",
63+
"@refref/email-templates": "workspace:*",
6264
"@refref/id": "workspace:*",
6365
"@refref/types": "workspace:*",
66+
"@refref/utils": "workspace:*",
6467
"@t3-oss/env-nextjs": "^0.10.1",
6568
"@tabler/icons-react": "^3.31.0",
6669
"@tanstack/react-form": "^1.19.3",
@@ -71,12 +74,12 @@
7174
"@trpc/server": "^11.4.4",
7275
"@tsndr/cloudflare-worker-jwt": "^3.1.4",
7376
"@uidotdev/usehooks": "^2.4.1",
74-
"better-auth": "^1.3.32",
77+
"better-auth": "^1.3.34",
7578
"class-variance-authority": "^0.7.1",
7679
"clsx": "^2.1.1",
7780
"cmdk": "1.0.0",
7881
"date-fns": "^4.1.0",
79-
"drizzle-orm": "^0.33.0",
82+
"drizzle-orm": "^0.44.7",
8083
"embla-carousel-react": "^8.5.2",
8184
"geist": "^1.3.0",
8285
"input-otp": "^1.4.2",
@@ -89,10 +92,10 @@
8992
"postgres": "^3.4.5",
9093
"posthog-js": "^1.281.0",
9194
"posthog-node": "^5.10.4",
92-
"react": "^19.0.0",
95+
"react": "^19.2.0",
9396
"react-aria-components": "^1.8.0",
9497
"react-day-picker": "8.10.1",
95-
"react-dom": "^19.0.0",
98+
"react-dom": "^19.2.0",
9699
"react-hook-form": "^7.54.2",
97100
"react-icons": "^5.5.0",
98101
"react-resizable-panels": "^2.1.7",
@@ -116,8 +119,8 @@
116119
"@refref/ui": "workspace:*",
117120
"@tailwindcss/postcss": "^4.0.14",
118121
"@types/node": "^24.3.0",
119-
"@types/react": "^19.1.9",
120-
"@types/react-dom": "^19.1.7",
122+
"@types/react": "^19.2.0",
123+
"@types/react-dom": "^19.2.0",
121124
"@typescript-eslint/eslint-plugin": "^8.1.0",
122125
"@typescript-eslint/parser": "^8.1.0",
123126
"@vitest/ui": "^2.1.8",

apps/webapp/src/lib/auth.ts

Lines changed: 18 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -1,180 +1,25 @@
1-
import { betterAuth } from "better-auth";
2-
import { drizzleAdapter } from "better-auth/adapters/drizzle";
3-
import { apiKey, magicLink, organization } from "better-auth/plugins";
4-
import { schema } from "@/server/db";
1+
import { getAuth } from "@refref/auth";
2+
import { db, schema } from "@/server/db";
53
import { env } from "@/env";
6-
import { db } from "@/server/db";
74
import { logger } from "@/lib/logger";
8-
import { emailService } from "@/lib/email";
95
import { posthog } from "@/lib/posthog";
106

11-
// Build social providers object dynamically based on enabled providers
12-
const socialProviders = env.NEXT_PUBLIC_ENABLED_SOCIAL_AUTH.reduce(
13-
(acc, provider) => {
14-
if (provider === "google") {
15-
return {
16-
...acc,
17-
google: {
18-
clientId: env.GOOGLE_CLIENT_ID,
19-
clientSecret: env.GOOGLE_CLIENT_SECRET,
20-
},
21-
};
22-
}
23-
// Add more providers here as needed (github, etc.)
24-
return acc;
25-
},
26-
{} as Record<string, { clientId: string; clientSecret: string }>,
27-
);
28-
29-
export const auth = betterAuth({
7+
// Create auth instance using the factory function from @refref/auth
8+
export const auth = getAuth({
309
baseURL: env.NEXT_PUBLIC_APP_URL,
31-
socialProviders,
32-
database: drizzleAdapter(db, {
33-
provider: "pg",
34-
schema: {
35-
...schema,
36-
},
37-
}),
38-
emailAndPassword: {
39-
enabled: env.NEXT_PUBLIC_ENABLE_PASSWORD_AUTH,
40-
},
10+
resendApiKey: env.RESEND_API_KEY || "debug_key",
11+
db,
12+
schema,
13+
enabledSocialAuth: env.NEXT_PUBLIC_ENABLED_SOCIAL_AUTH,
14+
enablePasswordAuth: env.NEXT_PUBLIC_ENABLE_PASSWORD_AUTH,
15+
enableMagicLinkAuth: env.NEXT_PUBLIC_ENABLE_MAGIC_LINK_AUTH,
16+
google: env.GOOGLE_CLIENT_ID
17+
? {
18+
clientId: env.GOOGLE_CLIENT_ID,
19+
clientSecret: env.GOOGLE_CLIENT_SECRET,
20+
}
21+
: undefined,
22+
logger,
23+
posthog,
4124
trustedOrigins: [env.NEXT_PUBLIC_APP_URL],
42-
/* emailVerification: {
43-
sendVerificationEmail: async ({ url }) => {
44-
console.log('verification link', url);
45-
}
46-
}, */
47-
emailProviders: {
48-
resend: {
49-
enabled: !!env.RESEND_API_KEY && env.RESEND_API_KEY !== "debug_key",
50-
apiKey: env.RESEND_API_KEY || "debug_key",
51-
autosignup: true,
52-
},
53-
},
54-
// socialProviders: {
55-
// github: {
56-
// clientId: process.env.GITHUB_CLIENT_ID!,
57-
// clientSecret: process.env.GITHUB_CLIENT_SECRET!,
58-
// }
59-
// },
60-
plugins: [
61-
...(env.NEXT_PUBLIC_ENABLE_MAGIC_LINK_AUTH
62-
? [
63-
magicLink({
64-
sendMagicLink: async ({ email, url }) => {
65-
try {
66-
logger.info("Sending magic link email", { url, email });
67-
const result = await emailService.sendMagicLink({ email, url });
68-
69-
if (!result.success) {
70-
throw (
71-
result.error || new Error("Failed to send magic link email")
72-
);
73-
}
74-
75-
logger.info("Magic link email sent successfully", { email });
76-
} catch (error) {
77-
console.error("Error sending magic link email", {
78-
error,
79-
email,
80-
});
81-
logger.error("Error sending magic link email", {
82-
error,
83-
email,
84-
});
85-
throw error;
86-
}
87-
},
88-
}),
89-
]
90-
: []),
91-
organization({
92-
schema: {
93-
organization: {
94-
modelName: "org",
95-
},
96-
session: {
97-
modelName: "session",
98-
fields: {
99-
activeOrganizationId: "activeOrganizationId",
100-
},
101-
},
102-
member: {
103-
modelName: "orgUser",
104-
fields: {
105-
organizationId: "orgId",
106-
},
107-
},
108-
invitation: {
109-
modelName: "invitation",
110-
fields: {
111-
organizationId: "organizationId",
112-
},
113-
},
114-
},
115-
async sendInvitationEmail({ id, email, role, inviter }) {
116-
const inviteLink = `${env.NEXT_PUBLIC_APP_URL}/accept-invitation/${id}`;
117-
logger.info("Sending invitation email", { inviteLink, email, role });
118-
119-
await emailService.sendInvitation({
120-
id,
121-
email,
122-
role,
123-
inviterName: inviter?.user?.name,
124-
inviterEmail: inviter?.user?.email,
125-
inviteLink,
126-
});
127-
},
128-
}),
129-
apiKey(),
130-
],
131-
databaseHooks: {
132-
user: {
133-
create: {
134-
after: async (user) => {
135-
// Track user signup event
136-
posthog.capture({
137-
distinctId: user.id,
138-
event: "user_sign_up",
139-
properties: {
140-
email: user.email,
141-
name: user.name || undefined,
142-
},
143-
});
144-
145-
// Auto-create default organization for new users
146-
try {
147-
const { org: orgTable, orgUser } = schema;
148-
149-
// Create default organization
150-
const [newOrg] = await db
151-
.insert(orgTable)
152-
.values({
153-
name: `${user.name || user.email}'s Organization`,
154-
slug: `org-${user.id.slice(0, 8)}`,
155-
})
156-
.returning();
157-
158-
// Add user as owner of the organization
159-
await db.insert(orgUser).values({
160-
orgId: newOrg!.id,
161-
userId: user.id,
162-
role: "owner",
163-
});
164-
165-
logger.info("Created default organization for new user", {
166-
userId: user.id,
167-
organizationId: newOrg!.id,
168-
});
169-
} catch (error) {
170-
logger.error("Failed to create default organization for user", {
171-
userId: user.id,
172-
error,
173-
});
174-
// Don't throw - allow user creation to succeed even if org creation fails
175-
}
176-
},
177-
},
178-
},
179-
},
18025
});

0 commit comments

Comments
 (0)