import { expo } from "@better-auth/expo"; import { env } from "@code/env/convex"; import { createClient } from "@convex-dev/better-auth"; import type { GenericCtx } from "@convex-dev/better-auth"; import { convex } from "@convex-dev/better-auth/plugins"; import { betterAuth } from "better-auth/minimal"; import { components } from "./_generated/api"; import type { DataModel } from "./_generated/dataModel"; import { query } from "./_generated/server"; import authConfig from "./auth.config"; const siteUrl = env.SITE_URL; const nativeAppUrl = env.NATIVE_APP_URL ?? "code://"; export const authComponent = createClient(components.betterAuth); const createAuth = (ctx: GenericCtx) => betterAuth({ baseURL: env.CONVEX_SITE_URL, database: authComponent.adapter(ctx), emailAndPassword: { enabled: true, requireEmailVerification: false, }, plugins: [ expo(), convex({ authConfig, jwksRotateOnTokenGenerationError: true, }), ], trustedOrigins: [siteUrl, nativeAppUrl, "exp://"], }); export { createAuth }; export interface AuthUserView { readonly id: string; readonly name: string; readonly email: string; } /** * Resolve the authenticated user to the canonical web view. The returned `id` * is the Convex `identity.tokenIdentifier`, the stable authenticated identity * used across organization/conversation/Signal ownership. Returns null when no * identity is present or the Better Auth user row cannot be resolved. */ export const getCurrentUser = query({ args: {}, handler: async (ctx): Promise => { const identity = await ctx.auth.getUserIdentity(); if (!identity) { return null; } const authUser = await authComponent.safeGetAuthUser(ctx); if (!authUser) { return null; } return { email: authUser.email, id: identity.tokenIdentifier, name: authUser.name, }; }, });