|
1 | | -import { |
2 | | - BetterAuth, |
3 | | - type AuthFunctions, |
4 | | - type PublicAuthFunctions, |
5 | | -} from '@convex-dev/better-auth' |
6 | | -import { api, components, internal } from './_generated/api' |
| 1 | +import { components, internal } from './_generated/api' |
7 | 2 | import { query, QueryCtx } from './_generated/server' |
8 | 3 | import type { Id, DataModel } from './_generated/dataModel' |
9 | 4 | import schema from './schema' |
10 | | - |
11 | | -import { Infer } from 'convex/values' |
| 5 | +import type { Infer } from 'convex/values' |
| 6 | +import { betterAuth } from 'better-auth' |
| 7 | +import { |
| 8 | + type AuthFunctions, |
| 9 | + type GenericCtx, |
| 10 | + createClient, |
| 11 | +} from '@convex-dev/better-auth' |
| 12 | +import { convex } from '@convex-dev/better-auth/plugins' |
12 | 13 |
|
13 | 14 | // Typesafe way to pass Convex functions defined in this file |
14 | 15 | const authFunctions: AuthFunctions = internal.auth |
15 | | -const publicAuthFunctions: PublicAuthFunctions = api.auth |
16 | 16 |
|
17 | 17 | // Initialize the component |
18 | | -export const betterAuthComponent = new BetterAuth(components.betterAuth, { |
| 18 | +export const authComponent = createClient<DataModel>(components.betterAuth, { |
19 | 19 | authFunctions, |
20 | | - publicAuthFunctions, |
| 20 | + triggers: { |
| 21 | + user: { |
| 22 | + onCreate: async (ctx, authUser) => { |
| 23 | + const userId = await ctx.db.insert('users', { |
| 24 | + createdAt: authUser.createdAt, |
| 25 | + email: authUser.email, |
| 26 | + updatedAt: authUser.updatedAt, |
| 27 | + displayUsername: authUser.displayUsername ?? '', |
| 28 | + image: authUser.image ?? '', |
| 29 | + name: authUser.name, |
| 30 | + capabilities: [], |
| 31 | + }) |
| 32 | + await authComponent.setUserId(ctx, authUser._id, userId) |
| 33 | + }, |
| 34 | + onUpdate: async (ctx, _, authUser) => { |
| 35 | + await ctx.db.patch(authUser.userId as Id<'users'>, { |
| 36 | + email: authUser.email, |
| 37 | + updatedAt: authUser.updatedAt, |
| 38 | + displayUsername: authUser.displayUsername ?? '', |
| 39 | + image: authUser.image ?? '', |
| 40 | + name: authUser.name, |
| 41 | + }) |
| 42 | + }, |
| 43 | + onDelete: async (ctx, authUser) => { |
| 44 | + await ctx.db.delete(authUser.userId as Id<'users'>) |
| 45 | + }, |
| 46 | + }, |
| 47 | + }, |
21 | 48 | }) |
22 | 49 |
|
23 | | -// These are required named exports |
24 | | -export const { |
25 | | - createUser, |
26 | | - updateUser, |
27 | | - deleteUser, |
28 | | - createSession, |
29 | | - isAuthenticated, |
30 | | -} = betterAuthComponent.createAuthFunctions<DataModel>({ |
31 | | - // Must create a user and return the user id |
32 | | - onCreateUser: async (ctx, user) => { |
33 | | - return ctx.db.insert('users', { |
34 | | - createdAt: user.createdAt, |
35 | | - email: user.email, |
36 | | - updatedAt: user.updatedAt, |
37 | | - displayUsername: user.displayUsername ?? '', |
38 | | - image: user.image ?? '', |
39 | | - name: user.name, |
40 | | - capabilities: [], |
41 | | - }) |
42 | | - }, |
| 50 | +export const { onCreate, onUpdate, onDelete } = authComponent.triggersApi() |
43 | 51 |
|
44 | | - // Delete the user when they are deleted from Better Auth |
45 | | - onDeleteUser: async (ctx, userId) => { |
46 | | - await ctx.db.delete(userId as Id<'users'>) |
47 | | - }, |
| 52 | +export const createAuth = ( |
| 53 | + ctx: GenericCtx<DataModel>, |
| 54 | + { optionsOnly } = { optionsOnly: false } |
| 55 | +) => |
| 56 | + betterAuth({ |
| 57 | + // All auth requests will be proxied through your TanStack Start server |
| 58 | + baseURL: process.env.URL, |
| 59 | + database: authComponent.adapter(ctx), |
48 | 60 |
|
49 | | - onUpdateUser: async (ctx, user) => { |
50 | | - await ctx.db.patch(user.userId as Id<'users'>, { |
51 | | - email: user.email, |
52 | | - updatedAt: user.updatedAt, |
53 | | - displayUsername: user.displayUsername ?? '', |
54 | | - image: user.image ?? '', |
55 | | - name: user.name, |
56 | | - }) |
57 | | - }, |
58 | | -}) |
| 61 | + logger: { |
| 62 | + disabled: optionsOnly, |
| 63 | + }, |
| 64 | + |
| 65 | + // Simple non-verified email/password to get started |
| 66 | + socialProviders: { |
| 67 | + github: { |
| 68 | + clientId: process.env.GITHUB_OAUTH_CLIENT_ID as string, |
| 69 | + clientSecret: process.env.GITHUB_OAUTH_CLIENT_SECRET as string, |
| 70 | + }, |
| 71 | + google: { |
| 72 | + clientId: process.env.GOOGLE_OAUTH_CLIENT_ID as string, |
| 73 | + clientSecret: process.env.GOOGLE_OAUTH_CLIENT_SECRET as string, |
| 74 | + }, |
| 75 | + }, |
| 76 | + plugins: [ |
| 77 | + // The Convex plugin is required |
| 78 | + convex(), |
| 79 | + ], |
| 80 | + }) |
59 | 81 |
|
60 | | -// Example function for getting the current user |
61 | | -// Feel free to edit, omit, etc. |
62 | 82 | export const getCurrentUser = query({ |
63 | 83 | args: {}, |
64 | 84 | handler: async (ctx) => { |
@@ -86,5 +106,5 @@ export type TanStackUser = Awaited<ReturnType<typeof getBetterAuthUser>> & |
86 | 106 | Infer<typeof schema.tables.users.validator> |
87 | 107 |
|
88 | 108 | function getBetterAuthUser(ctx: QueryCtx) { |
89 | | - return betterAuthComponent.getAuthUser(ctx) |
| 109 | + return authComponent.safeGetAuthUser(ctx) |
90 | 110 | } |
0 commit comments