#Betterauth / User table linking

9 messages · Page 1 of 1 (latest)

pallid gull
#

When using betterauth... what is the best approach to referencing the betterauth id in ones user table? The object passed to the onCreateUser callback does not contain any id, _id or userId fields. I'm assumming this pattern is common enough that there would be a pattern for it. What am I missing?

charred wadiBOT
#

Hi @pallid gull. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

When using Better Auth with Convex, the recommended approach for linking your app's user table to the Better Auth user table is to store the Better Auth user's ID (commonly called authId) in your app's user table. This is now the preferred pattern, as tracking your app's user ID in the Better Auth table (via user.userId) is deprecated and will be removed in future releases.

How to Link the Tables

  • Add an authId field to your app's user table. This field will store the Better Auth user's _id.
  • In your user creation trigger (onCreate), insert a new user in your app's table and set the authId to authUser._id. The authUser object passed to the trigger will contain the _id field.

Example:

export const authComponent = createClient<DataModel>(components.betterAuth, {
  authFunctions,
  triggers: {
    user: {
      onCreate: async (ctx, authUser) => {
        await ctx.db.insert("users", {
          email: authUser.email,
          authId: authUser._id, // Link to Better Auth user
        });
      },
    },
  },
});
  • Update your queries to use the authId field when looking up users.

Example:

const user = await ctx.db
  .query("users")
  .withIndex("authId", (q) => q.eq("authId", authUser._id))
  .unique();

Why doesn't onCreateUser have an ID?

The onCreateUser callback (from older versions) did not provide the Better Auth user ID because the user record had not yet been created. With the new triggers system, the onCreate trigger receives the full authUser object, including _id, after the user is created, which solves this problem and is the recommended approach going forward.

#

Summary:
Store the Better Auth user's _id as authId in your app's user table during the onCreate trigger. This is the current best practice and is well-supported by the latest versions of Better Auth and Convex. For more details and migration steps, see the migration guide and triggers documentation.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@pallid gull Kapa.ai is still learning and improving, please let me know how I did by reacting below.

pallid gull
#

Thanks @charred wadi . I have updated my project but the _id field is still throwing a type error on the object returned in the onCreateUser hook. Is this a known error at the moment? --> Property '_id' does not exist on type '{ image?: string | null | undefined; twoFactorEnabled?: boolean | null | undefined; isAnonymous?: boolean | null | undefined; username?: string | null | undefined; displayUsername?: string | ... 1 more ... | undefined; ... 12 more ...; updatedAt: number; }'.ts(

charred wadiBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

Yes, this is a known issue that has come up in the community. The problem is that in older versions of Better Auth, the onCreateUser callback did not provide the Better Auth user’s _id field, because the user record had not yet been created at the time the callback was invoked. As a result, the object passed to onCreateUser does not include _id, and TypeScript will throw a type error if you try to access it.

The recommended solution is to migrate to the new triggers system, where the onCreate trigger receives the full authUser object, including the _id field, after the user is created. This resolves the type error and is the current best practice. Here’s an example of the new pattern:

export const authComponent = createClient<DataModel>(components.betterAuth, {
  authFunctions,
  triggers: {
    user: {
      onCreate: async (ctx, authUser) => {
        await ctx.db.insert("users", {
          email: authUser.email,
          authId: authUser._id, // This is now available and correctly typed
        });
      },
    },
  },
});

If you are still using the old onCreateUser hook, you will not have access to _id and will encounter this type error. Migrating to the new triggers system is the recommended fix, as described in the migration guide and triggers documentation.

If you have already migrated and are still seeing this error, double-check that you are using the new onCreate trigger and not the deprecated onCreateUser hook, and that your dependencies are up to date. If the issue persists, it may be a type generation or version mismatch issue, in which case regenerating your schema and ensuring all packages are on the latest versions is recommended.

#

Summary:

  • The type error is expected with the old onCreateUser hook.
  • Switch to the new onCreate trigger, which provides the _id field.
  • Make sure your dependencies and generated types are up to date.

For more details, see the migration guide and triggers example.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: