Raypx

Email Verification & Password Reset

Email verification on sign-up and password reset flow.

Raypx sends verification emails on sign-up and supports a full password reset flow. Both features are powered by the @raypx/email package using React Email templates sent through Resend.

Email Verification

When a user signs up, a verification email is sent automatically. The configuration in packages/auth/src/index.ts:

packages/auth/src/index.ts
emailVerification: {
  autoSignInAfterVerification: true,
  sendOnSignUp: true,
  sendVerificationEmail: async ({ user, url }) => {
    await sendVerificationEmail({ email: user.email, name: user.name, url })
  },
},

Key behaviors:

  • sendOnSignUp: true -- A verification email is sent immediately when a user registers.
  • autoSignInAfterVerification: true -- After the user clicks the verification link, they are signed in automatically and redirected to the app.

Verification Flow

The user fills in name, email, and password. A new account is created in the user table with emailVerified set to false.

The sendVerificationEmail function in packages/auth/src/email.ts renders the template and sends it via Resend.

The link points to /api/auth/verify-email. Better Auth validates the token from the verification table.

The emailVerified field is set to true. Because autoSignInAfterVerification is enabled, the user is signed in and redirected.

Password Reset

The password reset flow allows users to reset their password via email.

Reset Configuration

packages/auth/src/index.ts
emailAndPassword: {
  resetPasswordTokenExpiresIn: 60 * 60, // 1 hour
  revokeSessionsOnPasswordReset: true,
  sendResetPassword: async ({ user, url }) => {
    await sendPasswordResetEmail({ email: user.email, name: user.name, url })
  },
  onPasswordReset: async ({ user }) => {
    logger.info("auth.password.reset", { feature: "auth", userId: user.id })
  },
},

Reset Flow

The user navigates to /forgot-password and enters their email address.

If the email exists in the database, a reset email is sent. The token expires in 1 hour.

The user clicks the link and is taken to /reset-password where they enter a new password.

All existing sessions are invalidated (revokeSessionsOnPasswordReset: true). The user must sign in again with the new password.

When revokeSessionsOnPasswordReset is true, all active sessions across all devices are terminated. This is a security measure to ensure that if a password was compromised, the attacker loses access immediately.

Email Templates

Templates live in packages/email/src/templates/ and follow the React Email component pattern:

Template Pattern

Each template exports an async function that returns { subject, html, text }:

packages/email/src/templates/password-reset.tsx
import { Body, Button, Container, Head, Html, Preview, Section, Text } from "@react-email/components"
import { render } from "@react-email/render"

export type PasswordResetTemplateInput = {
  name: string
  url: string
}

export const passwordResetTemplate: AsyncEmailTemplate<PasswordResetTemplateInput> = async (input) => {
  const { name, url } = input
  const element = <PasswordResetEmail name={name} url={url} />
  const html = await render(element, { pretty: false })

  return {
    subject: "Reset your password",
    html,
    text: `Hi ${name},\n\nWe received a request to reset your password...`,
  }
}

function PasswordResetEmail({ name, url }: PasswordResetTemplateInput) {
  return (
    <Html>
      <Head />
      <Preview>Reset your password - {name}</Preview>
      <Body style={main}>
        <Container style={container}>
          <Section style={header}>
            <Text style={titleStyle}>Reset your password</Text>
          </Section>
          <Section style={bodySection}>
            <Text style={textStyle}>Hi {name},</Text>
            <Text style={textStyle}>
              Click the button below to choose a new one:
            </Text>
            <Button href={url} style={buttonStyle}>Reset Password</Button>
          </Section>
        </Container>
      </Body>
    </Html>
  )
}

Customizing Templates

To customize the look and feel:

  1. Edit the inline styles in the template component (main, container, buttonStyle, etc.).
  2. Set EMAIL_TEMPLATES_BASE_URL in your .env to show a "Sent from" footer.
  3. Modify the subject and text fallback content.

Adding a New Template

  1. Create a new .tsx file in packages/email/src/templates/.
  2. Follow the same pattern: define input types, export an async template function.
  3. Export it from packages/email/src/templates/index.ts.
  4. Call it from the appropriate auth callback in packages/auth/src/email.ts.

Email Sending

Emails are sent through the @raypx/email package, which supports multiple transports:

On this page