Skip to main content

Overview

WAHA Dashboard implements a secure authentication system using Better Auth with email/password authentication and role-based access control. New users register as guests and must be approved by administrators before gaining full access.

User Roles

The system supports three distinct user roles with different permission levels:

Admin

Full system access including user management, session monitoring, and campaign oversight

User

Can create and manage campaigns, schedule messages, and view their own sessions

Guest

Limited access - awaiting admin approval to become a User

Role Definitions

prisma/schema.prisma:13
enum UserRole {
  ADMIN
  USER
  GUEST
}
All new registrations default to the GUEST role and require admin approval:
src/server/auth.ts:21
user: {
  additionalFields: {
    role: {
      type: "string",
      required: false,
      defaultValue: "GUEST",
      input: false,
      output: true,
    },
  },
}

Sign Up Flow

1

User Registration

New users register with their name, email, and password. The account is created with the GUEST role.
2

Admin Notification

The system sends dual-channel notifications to admins:
  • WhatsApp message (primary)
  • Email notification (fallback)
3

Admin Approval

Admins review pending registrations in the admin dashboard and approve or reject access.
4

Account Activation

Once approved, the user’s role changes from GUEST to USER, granting full platform access.

Registration Notifications

When a new user registers, administrators are automatically notified:
src/server/mailgun.ts:496
export async function notifyAdminOfNewRegistration(userName: string, userEmail: string) {
  const results = { whatsapp: false, email: false, errors: [] as string[] };

  try {
    await sendWhatsAppNotificationToAdmin(userName, userEmail);
    results.whatsapp = true;
  } catch (error) {
    // Fallback to email if WhatsApp fails
    try {
      await sendUserRegistrationNotificationToAdmin(userName, userEmail);
      results.email = true;
    } catch (error) {
      results.errors.push(`Email failed: ${error.message}`);
    }
  }

  return results;
}
The system attempts WhatsApp notification first, then falls back to email if WhatsApp delivery fails. This ensures admins are always notified of pending registrations.

Login Flow

Authenticated users can log in using their email and password:
src/server/auth.ts:9
emailAndPassword: {
  enabled: true,
  requireEmailVerification: false,
}
Email verification is currently disabled. Consider enabling it in production for enhanced security.

Password Management

Password Reset

Users can request password reset links via email:
src/server/auth.ts:12
sendResetPassword: async ({user, url}) => {
  await sendResetPasswordEmail(user.email, url);
}
The reset email includes:
  • Secure reset link (expires in 1 hour)
  • Security warning about unsolicited requests
  • Branded HTML email template

Password Change Notifications

When a password is successfully changed, users receive a confirmation email for security purposes:
src/server/mailgun.ts:162
export async function sendPasswordChangedNotification(email: string) {
  const emailData = {
    from: env.FROM_EMAIL,
    to: email,
    subject: "Password Changed Successfully - WhatsApp Group Manager",
    // ... HTML template
  };
  
  await mg.messages.create(env.MAILGUN_DOMAIN, emailData);
}

Session Management

Sessions are stored in MongoDB with tracking metadata:
prisma/schema.prisma:133
model Session {
  id        String   @id @default(cuid())
  expiresAt DateTime
  token     String   @unique
  createdAt DateTime
  updatedAt DateTime
  ipAddress String?
  userAgent String?
  userId    String
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}
  • Automatic expiration tracking
  • IP address and user agent logging
  • Cascade deletion when user is removed
  • Unique token generation

Database Configuration

Authentication uses Prisma with MongoDB:
src/server/auth.ts:16
database: prismaAdapter(prisma, {
  provider: "mongodb",
})

Protected Routes

The application uses tRPC procedures with role-based protection:
  • publicProcedure - Available to all users
  • protectedProcedure - Requires authenticated user (USER or ADMIN role)
  • adminProcedure - Requires ADMIN role only
import { protectedProcedure } from "../trpc";

export const userRouter = createTRPCRouter({
  getCampaigns: protectedProcedure
    .query(async ({ ctx }) => {
      // Only authenticated users can access
      return ctx.db.messageCampaign.findMany({
        where: {
          session: { userId: ctx.session.user.id }
        }
      });
    }),
});

Security Best Practices

  • Minimum 8 characters
  • Maximum 100 characters
  • Consider implementing complexity requirements in production
  • Admin accounts cannot be deleted
  • Admin access cannot be revoked
  • Sessions cascade delete with user accounts
  • Password reset links expire in 1 hour
  • Users notified of password changes
  • No reply-to address to prevent phishing

Next Steps

Admin Dashboard

Learn about user approval and admin features

Notifications

Explore multi-channel notification system

Build docs developers (and LLMs) love