# MystBin ! - signup.tsx
"use client";
import { getInputProps, useForm, type FieldMetadata } from "@conform-to/react";
import { getZodConstraint, parseWithZod } from "@conform-to/zod";
import { signup } from "~/app/actions/auth";
import { signupSchema } from "~/lib/schema/auth";
import { useActionState } from "react";
import { type z } from "zod";
import { Button } from "./ui/button";
import { Input } from "./ui/input";
import { Label } from "./ui/label";
export function SignupForm() {
const [lastResult, action, isSubmitting] = useActionState(signup, undefined);
const [form, fields] = useForm({
id: "signup",
lastResult,
constraint: getZodConstraint(signupSchema),
shouldValidate: "onBlur",
onValidate({ formData }) {
return parseWithZod(formData, { schema: signupSchema });
},
});
return (
);
}
function Field({
field,
label,
placeholder,
type,
}: {
field: FieldMetadata, string[]>;
label: string;
placeholder?: string;
type: "email" | "password" | "text";
}) {
const { key, ...inputProps } = getInputProps(field, { type });
return (
);
}
# MystBin ! - actions/auth.ts
"use client";
import { getInputProps, useForm, type FieldMetadata } from "@conform-to/react";
import { getZodConstraint, parseWithZod } from "@conform-to/zod";
import { signup } from "~/app/actions/auth";
import { signupSchema } from "~/lib/schema/auth";
import { useActionState } from "react";
import { type z } from "zod";
import { Button } from "./ui/button";
import { Input } from "./ui/input";
import { Label } from "./ui/label";
export function SignupForm() {
const [lastResult, action, isSubmitting] = useActionState(signup, undefined);
const [form, fields] = useForm({
id: "signup",
lastResult,
constraint: getZodConstraint(signupSchema),
shouldValidate: "onBlur",
onValidate({ formData }) {
return parseWithZod(formData, { schema: signupSchema });
},
});
return (
);
}
function Field({
field,
label,
placeholder,
type,
}: {
field: FieldMetadata, string[]>;
label: string;
placeholder?: string;
type: "email" | "password" | "text";
}) {
const { key, ...inputProps } = getInputProps(field, { type });
return (
);
}
# MystBin ! - auth/config.ts
import { env } from "~/env";
import { db } from "~/server/db";
import {
account,
rateLimit,
session,
user,
verification,
} from "~/server/db/schema";
import { api } from "~/trpc/server";
import { type BetterAuthOptions } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { nextCookies } from "better-auth/next-js";
export const authConfig = {
baseURL: env.URL,
appName: "Kapil Jewels",
advanced: {
generateId: false,
useSecureCookies: true,
defaultCookieAttributes: {
secure: true,
httpOnly: true,
sameSite: "lax",
},
},
database: drizzleAdapter(db, {
provider: "pg",
schema: {
user,
account,
session,
verification,
rateLimit,
},
}),
emailVerification: {
expiresIn: 60 * 10,
sendOnSignUp: true,
async sendVerificationEmail(data) {
console.log(data);
// await api.resend.verify({ email: data.user.email, url: data.url });
},
},
emailAndPassword: {
enabled: true,
autoSignIn: true,
resetPasswordTokenExpiresIn: 60 * 10,
async sendResetPassword(data) {
console.log(data);
// await api.resend.resetPassword({ email: data.user.email, url: data.url });
},
},
rateLimit: {
storage: "database",
window: 60,
max: 10,
},
session: {
expiresIn: 30 * 24 * 60 * 60,
updateAge: 15 * 24 * 60 * 60,
cookieCache: {
enabled: true,
maxAge: 60 * 10,
},
},
plugins: [nextCookies()],
} satisfies BetterAuthOptions;
# MystBin ! - auth/index.ts
import { betterAuth } from "better-auth";
import { cache } from "react";
import { authConfig } from "./config";
const {
handler,
api: { getSession: uncachedGetSession, signInEmail, signOut, signUpEmail },
} = betterAuth(authConfig);
const getSession = cache(uncachedGetSession);
export { handler, getSession, signInEmail, signOut, signUpEmail };