Initial push
This commit is contained in:
48
lib/auth/client.ts
Normal file
48
lib/auth/client.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
"use client";
|
||||
|
||||
import { createAuthClient } from "better-auth/react";
|
||||
import { organizationClient } from "better-auth/client/plugins";
|
||||
import { magicLinkClient } from "better-auth/client/plugins";
|
||||
import type { Auth } from "./index";
|
||||
|
||||
/**
|
||||
* Better Auth client instance for use in React components and client-side
|
||||
* code. Mirrors the plugins registered on the server-side `auth` instance.
|
||||
*/
|
||||
export const authClient = createAuthClient({
|
||||
baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL ?? "http://localhost:3000",
|
||||
|
||||
plugins: [
|
||||
// Enables organization.* methods (createOrganization, getActiveMember, etc.)
|
||||
organizationClient(),
|
||||
|
||||
// Enables signIn.magicLink and magicLink.verify
|
||||
magicLinkClient(),
|
||||
],
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Convenience re-exports so consumers only need to import from this module
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const {
|
||||
signIn,
|
||||
signOut,
|
||||
signUp,
|
||||
useSession,
|
||||
getSession,
|
||||
} = authClient;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Inferred client-side types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export type ClientSession = typeof authClient.$Infer.Session.session;
|
||||
export type ClientUser = typeof authClient.$Infer.Session.user;
|
||||
|
||||
/**
|
||||
* Infer server plugin types on the client side.
|
||||
* Provides full type safety for plugin-specific methods without importing
|
||||
* the server-only `auth` instance into a client bundle.
|
||||
*/
|
||||
export type { Auth };
|
||||
108
lib/auth/index.ts
Normal file
108
lib/auth/index.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { betterAuth } from "better-auth";
|
||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||
import { organization } from "better-auth/plugins";
|
||||
import { magicLink } from "better-auth/plugins/magic-link";
|
||||
import { db } from "@/lib/db";
|
||||
import * as schema from "@/lib/db/schema";
|
||||
|
||||
const isProduction = process.env.NODE_ENV === "production";
|
||||
|
||||
export const auth = betterAuth({
|
||||
// -------------------------------------------------------------------------
|
||||
// Core
|
||||
// -------------------------------------------------------------------------
|
||||
secret: process.env.BETTER_AUTH_SECRET!,
|
||||
baseURL: process.env.BETTER_AUTH_URL ?? "http://localhost:3000",
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Database adapter (Drizzle + bun:sqlite)
|
||||
// -------------------------------------------------------------------------
|
||||
database: drizzleAdapter(db, {
|
||||
provider: "sqlite",
|
||||
schema: {
|
||||
users: schema.users,
|
||||
sessions: schema.sessions,
|
||||
accounts: schema.accounts,
|
||||
verifications: schema.verifications,
|
||||
},
|
||||
usePlural: false,
|
||||
}),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Custom user fields
|
||||
// -------------------------------------------------------------------------
|
||||
user: {
|
||||
additionalFields: {
|
||||
role: {
|
||||
type: "string",
|
||||
required: false,
|
||||
defaultValue: "moderator",
|
||||
input: false, // Not settable by the user directly
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Email + password authentication
|
||||
// -------------------------------------------------------------------------
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
requireEmailVerification: false,
|
||||
minPasswordLength: 8,
|
||||
maxPasswordLength: 128,
|
||||
},
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Plugins
|
||||
// -------------------------------------------------------------------------
|
||||
plugins: [
|
||||
// Organization / role support
|
||||
organization(),
|
||||
|
||||
// Magic link — used for invitation acceptance flows
|
||||
magicLink({
|
||||
expiresIn: 60 * 60, // 1 hour
|
||||
disableSignUp: true, // magic links are only for invited users
|
||||
sendMagicLink: async ({ email, url, token }) => {
|
||||
// Delegate to the application's email module. The email module is
|
||||
// responsible for importing and calling Resend (or whichever mailer
|
||||
// is configured). We do a dynamic import so that this file does not
|
||||
// pull in email dependencies at auth-initialisation time on the edge.
|
||||
const { sendMagicLinkEmail } = await import("@/lib/email/index");
|
||||
await sendMagicLinkEmail({ email, url, token });
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Trusted origins — allow env-configured list plus localhost in dev
|
||||
// -------------------------------------------------------------------------
|
||||
trustedOrigins: process.env.BETTER_AUTH_TRUSTED_ORIGINS
|
||||
? process.env.BETTER_AUTH_TRUSTED_ORIGINS.split(",").map((o) => o.trim())
|
||||
: ["http://localhost:3000"],
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Cookie / session security
|
||||
// -------------------------------------------------------------------------
|
||||
advanced: {
|
||||
useSecureCookies: isProduction,
|
||||
defaultCookieAttributes: {
|
||||
httpOnly: true,
|
||||
secure: isProduction,
|
||||
sameSite: "strict",
|
||||
path: "/",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type helpers for use across the application
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export type Auth = typeof auth;
|
||||
|
||||
/** The server-side session type returned by auth.api.getSession */
|
||||
export type Session = typeof auth.$Infer.Session.session;
|
||||
|
||||
/** The user type embedded in every session */
|
||||
export type User = typeof auth.$Infer.Session.user;
|
||||
Reference in New Issue
Block a user