This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// The component's database functions over the locally installed schema.
|
||||
import { createApi } from "@convex-dev/better-auth"
|
||||
import { createAuthOptions } from "../auth"
|
||||
import schema from "./schema"
|
||||
|
||||
export const { create, findOne, findMany, updateOne, updateMany, deleteOne, deleteMany } = createApi(
|
||||
schema,
|
||||
createAuthOptions,
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// The Better Auth component, installed locally (@convex-dev/better-auth "local install"): its tables
|
||||
// are ./schema.ts, generated from this app's own Better Auth options (./options.ts).
|
||||
import { defineComponent } from "convex/server"
|
||||
|
||||
const component = defineComponent("betterAuth")
|
||||
export default component
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// What of this app's Better Auth configuration shapes its tables. ./schema.ts is generated from it
|
||||
// (test/better-auth.test.ts checks the two agree; `pnpm exec vitest run test/better-auth.test.ts -u`
|
||||
// regenerates the schema after a change here), and ../auth.ts builds Better Auth with it.
|
||||
//
|
||||
// - email and password sign-in, without e-mail verification (an app that sends mail turns it on)
|
||||
// - the person's own account deletion (`/delete-user`): the revocation relay hands it to the app's
|
||||
// account flow, which erases the person's data in every module (apps/web/src/server/better-auth.ts)
|
||||
// - the admin plugin: an administrator disables (`banned`) a user, which ends every session of the
|
||||
// user and refuses the next sign-in; the session validation refuses a disabled user as well
|
||||
// - rate limits kept in the deployment's own table, since a Convex function keeps no memory
|
||||
import { convex } from "@convex-dev/better-auth/plugins"
|
||||
import type { BetterAuthOptions } from "better-auth/minimal"
|
||||
import { admin } from "better-auth/plugins/admin"
|
||||
import type { AuthConfig } from "convex/server"
|
||||
|
||||
export const MIN_PASSWORD_LENGTH = 12
|
||||
|
||||
/** The administrators the admin plugin accepts, by Better Auth user ID (BETTER_AUTH_ADMIN_USER_IDS, comma-separated). */
|
||||
const adminUserIds = (): string[] =>
|
||||
(process.env.BETTER_AUTH_ADMIN_USER_IDS ?? "")
|
||||
.split(",")
|
||||
.map((id) => id.trim())
|
||||
.filter(Boolean)
|
||||
|
||||
export function betterAuthOptions(authConfig: AuthConfig) {
|
||||
return {
|
||||
emailAndPassword: { enabled: true, requireEmailVerification: false, minPasswordLength: MIN_PASSWORD_LENGTH },
|
||||
user: { deleteUser: { enabled: true } },
|
||||
rateLimit: { enabled: true, storage: "database" },
|
||||
plugins: [convex({ authConfig }), admin({ adminUserIds: adminUserIds() })],
|
||||
} satisfies Omit<BetterAuthOptions, "database">
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// Generated from ./options.ts by the @convex-dev/better-auth schema generator: do not edit it by hand.
|
||||
// After a change of the Better Auth options, regenerate it with
|
||||
// pnpm exec vitest run test/better-auth.test.ts -u
|
||||
// (the "local install" of @convex-dev/better-auth, which is how the admin plugin's fields get here).
|
||||
|
||||
import { defineSchema, defineTable } from "convex/server";
|
||||
import { v } from "convex/values";
|
||||
|
||||
export const tables = {
|
||||
user: defineTable({
|
||||
name: v.string(),
|
||||
email: v.string(),
|
||||
emailVerified: v.boolean(),
|
||||
image: v.optional(v.union(v.null(), v.string())),
|
||||
createdAt: v.number(),
|
||||
updatedAt: v.number(),
|
||||
userId: v.optional(v.union(v.null(), v.string())),
|
||||
role: v.optional(v.union(v.null(), v.string())),
|
||||
banned: v.optional(v.union(v.null(), v.boolean())),
|
||||
banReason: v.optional(v.union(v.null(), v.string())),
|
||||
banExpires: v.optional(v.union(v.null(), v.number())),
|
||||
})
|
||||
.index("email_name", ["email","name"])
|
||||
.index("name", ["name"])
|
||||
.index("userId", ["userId"]),
|
||||
session: defineTable({
|
||||
expiresAt: v.number(),
|
||||
token: v.string(),
|
||||
createdAt: v.number(),
|
||||
updatedAt: v.number(),
|
||||
ipAddress: v.optional(v.union(v.null(), v.string())),
|
||||
userAgent: v.optional(v.union(v.null(), v.string())),
|
||||
userId: v.string(),
|
||||
impersonatedBy: v.optional(v.union(v.null(), v.string())),
|
||||
})
|
||||
.index("expiresAt", ["expiresAt"])
|
||||
.index("expiresAt_userId", ["expiresAt","userId"])
|
||||
.index("token", ["token"])
|
||||
.index("userId", ["userId"]),
|
||||
account: defineTable({
|
||||
accountId: v.string(),
|
||||
providerId: v.string(),
|
||||
userId: v.string(),
|
||||
accessToken: v.optional(v.union(v.null(), v.string())),
|
||||
refreshToken: v.optional(v.union(v.null(), v.string())),
|
||||
idToken: v.optional(v.union(v.null(), v.string())),
|
||||
accessTokenExpiresAt: v.optional(v.union(v.null(), v.number())),
|
||||
refreshTokenExpiresAt: v.optional(v.union(v.null(), v.number())),
|
||||
scope: v.optional(v.union(v.null(), v.string())),
|
||||
password: v.optional(v.union(v.null(), v.string())),
|
||||
createdAt: v.number(),
|
||||
updatedAt: v.number(),
|
||||
})
|
||||
.index("accountId", ["accountId"])
|
||||
.index("accountId_providerId", ["accountId","providerId"])
|
||||
.index("providerId_userId", ["providerId","userId"])
|
||||
.index("userId", ["userId"]),
|
||||
verification: defineTable({
|
||||
identifier: v.string(),
|
||||
value: v.string(),
|
||||
expiresAt: v.number(),
|
||||
createdAt: v.number(),
|
||||
updatedAt: v.number(),
|
||||
})
|
||||
.index("expiresAt", ["expiresAt"])
|
||||
.index("identifier", ["identifier"]),
|
||||
jwks: defineTable({
|
||||
publicKey: v.string(),
|
||||
privateKey: v.string(),
|
||||
createdAt: v.number(),
|
||||
expiresAt: v.optional(v.union(v.null(), v.number())),
|
||||
}),
|
||||
rateLimit: defineTable({
|
||||
key: v.string(),
|
||||
count: v.number(),
|
||||
lastRequest: v.number(),
|
||||
})
|
||||
.index("key", ["key"]),
|
||||
};
|
||||
|
||||
const schema = defineSchema(tables);
|
||||
|
||||
export default schema;
|
||||
Reference in New Issue
Block a user