Configure email/password authentication with email verification, password reset, and customizable validation rules.
Email & password is the most common authentication method. Banata Auth provides a complete implementation with email verification, password reset, configurable validation, and automatic audit logging.
Configuration
Enable email/password authentication in your BanataAuthConfig:
Keep the auth email types enabled in Emails > Configuration
Customize the built-in templates in Email Templates
Call the auth client from your frontend
Verification and password-reset emails are then sent automatically by Banata. Developers should not need to write Resend, SendGrid, or provider-specific code for the normal setup.
Optional Code Overrides
If you want to bypass the dashboard-managed delivery path for a specific project, add callbacks in config.email. These callbacks override Banata's automatic sending for that email type.
await authClient.signOut();// Session cookie is cleared, redirect to sign-inwindow.location.href = "/sign-in";
Request Password Reset
typescript
const { error } = await authClient.forgetPassword({ email: "user@example.com", redirectTo: "/reset-password", // Where to redirect after clicking reset link});if (error) { console.error(error.message);} else { // Email sent — show confirmation message}
Reset Password (with token from email)
typescript
// On the /reset-password page, extract the token from URL paramsconst token = new URLSearchParams(window.location.search).get("token");const { error } = await authClient.resetPassword({ newPassword: "newSecurePassword456", token: token!,});if (error) { // "Invalid or expired token" (400) // "Password too short" (422) console.error(error.message);} else { // Password updated — redirect to sign-in window.location.href = "/sign-in";}
Verify Email
Email verification typically happens automatically when the user clicks the link in the verification email. The link hits the /api/auth/verify-email endpoint with the token, and Better Auth handles the verification.
If you need to resend the verification email:
typescript
const { error } = await authClient.sendVerificationEmail({ email: "user@example.com", callbackURL: "/dashboard", // Where to redirect after verification});
Password Validation
Banata Auth validates passwords using the passwordSchema from @banata-auth/shared:
Rule
Default
Minimum length
8 characters
Maximum length
128 characters
Type
String
The validation is applied on both sign-up and password reset. If a password doesn't meet the requirements, a ValidationError (422) is returned.
Custom Password Rules
To enforce additional rules (uppercase, numbers, special characters), you can add custom validation in your sign-up form before calling the API:
typescript
function validatePassword(password: string): string | null { if (password.length < 8) return "Password must be at least 8 characters"; if (password.length > 128) return "Password must be at most 128 characters"; if (!/[A-Z]/.test(password)) return "Password must contain an uppercase letter"; if (!/[0-9]/.test(password)) return "Password must contain a number"; if (!/[^A-Za-z0-9]/.test(password)) return "Password must contain a special character"; return null; // Valid}
Pre-Built UI Components
Banata Auth ships a SignUpForm and SignInForm in @banata-auth/react that handle the entire email/password flow:
Sign Up Form
tsx
import { SignUpForm } from "@banata-auth/react";import { authClient } from "@/lib/auth-client";export default function SignUpPage() { return ( <SignUpForm authClient={authClient} onSuccess={() => { window.location.href = "/dashboard"; }} onError={(error) => { console.error("Sign up failed:", error.message); }} /> );}
Sign In Form
tsx
import { SignInForm } from "@banata-auth/react";import { authClient } from "@/lib/auth-client";export default function SignInPage() { return ( <SignInForm authClient={authClient} onSuccess={() => { window.location.href = "/dashboard"; }} onError={(error) => { console.error("Sign in failed:", error.message); }} /> );}
Note: The pre-built forms use window.location.href for navigation after success (hard navigation, not client-side routing). This ensures the session cookie is properly read on the next page load.
Server-Side User Management
Use the admin SDK to manage users from your backend:
typescript
import { BanataAuth } from "@banata-auth/sdk";const banata = new BanataAuth({ apiKey: "your-api-key", baseUrl: "https://your-deployment.convex.site",});// Create a user programmaticallyconst user = await banata.users.createUser({ projectId: "proj_01HXYZ...", email: "admin@example.com", password: "securePassword123", name: "Admin User", role: "admin",});// List all users (paginated)const { data, listMetadata } = await banata.users.listUsers({ limit: 20,});// Get a specific userconst user = await banata.users.getUser({ userId: "usr_01HXYZ..." });// Update a userawait banata.users.updateUser({ userId: "usr_01HXYZ...", name: "Updated Name", metadata: { plan: "pro" },});// Ban a userawait banata.users.banUser({ userId: "usr_01HXYZ..." });// Delete a userawait banata.users.deleteUser({ userId: "usr_01HXYZ..." });
Override Delivery With Your Own Provider Code
Most teams should configure providers in the Banata dashboard and let Banata send auth emails automatically. Use code like this only if you deliberately want your app to own delivery.
// Note: AWS SES requires signing requests with SigV4.// Consider using the AWS SDK or a wrapper service.
Important: Email override callbacks run inside Convex functions, which means you can only use fetch() — you cannot use Node.js-specific libraries like nodemailer. If you do not need a custom delivery path, leave these callbacks out and use the dashboard-managed provider instead.
Audit Events
When email/password auth is enabled, the following events are automatically logged to the audit log: