AgentStack
SKILL verified MIT Self-run

Email And Password Best Practices

skill-svssdeva-agentic-skills-email-and-password-best-practices · by svssdeva

A Claude skill from svssdeva/agentic-skills.

No reviews yet
0 installs
3 views
0.0% view→install

Install

$ agentstack add skill-svssdeva-agentic-skills-email-and-password-best-practices

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Email And Password Best Practices? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About


name: email-and-password-best-practices description: Configure email verification, implement password reset flows, set password policies, and customise hashing algorithms for Better Auth email/password authentication. Use when users need to set up login, sign-in, sign-up, credential authentication, or password security with Better Auth. ---

Quick Start

  1. Enable email/password: emailAndPassword: { enabled: true }
  2. Configure emailVerification.sendVerificationEmail
  3. Add sendResetPassword for password reset flows
  4. Run npx @better-auth/cli@latest migrate
  5. Verify: attempt sign-up and confirm verification email triggers

Email Verification Setup

Configure emailVerification.sendVerificationEmail to verify user email addresses.

import { betterAuth } from "better-auth";
import { sendEmail } from "./email"; // your email sending function

export const auth = betterAuth({
  emailVerification: {
    sendVerificationEmail: async ({ user, url, token }, request) => {
      await sendEmail({
        to: user.email,
        subject: "Verify your email address",
        text: `Click the link to verify your email: ${url}`,
      });
    },
  },
});

Note: The url parameter contains the full verification link. The token is available if you need to build a custom verification URL.

Requiring Email Verification

For stricter security, enable emailAndPassword.requireEmailVerification to block sign-in until the user verifies their email. When enabled, unverified users will receive a new verification email on each sign-in attempt.

export const auth = betterAuth({
  emailAndPassword: {
    requireEmailVerification: true,
  },
});

Note: This requires sendVerificationEmail to be configured and only applies to email/password sign-ins.

Client Side Validation

Implement client-side validation for immediate user feedback and reduced server load.

Callback URLs

Always use absolute URLs (including the origin) for callback URLs in sign-up and sign-in requests. This prevents Better Auth from needing to infer the origin, which can cause issues when your backend and frontend are on different domains.

const { data, error } = await authClient.signUp.email({
  callbackURL: "https://example.com/callback", // absolute URL with origin
});

Password Reset Flows

Provide sendResetPassword in the email and password config to enable password resets.

import { betterAuth } from "better-auth";
import { sendEmail } from "./email"; // your email sending function

export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    // Custom email sending function to send reset-password email
    sendResetPassword: async ({ user, url, token }, request) => {
      void sendEmail({
        to: user.email,
        subject: "Reset your password",
        text: `Click the link to reset your password: ${url}`,
      });
    },
    // Optional event hook
    onPasswordReset: async ({ user }, request) => {
      // your logic here
      console.log(`Password for user ${user.email} has been reset.`);
    },
  },
});

Security Considerations

Built-in protections: background email sending (timing attack prevention), dummy operations on invalid requests, constant response messages regardless of user existence.

On serverless platforms, configure a background task handler:

export const auth = betterAuth({
  advanced: {
    backgroundTasks: {
      handler: (promise) => {
        // Use platform-specific methods like waitUntil
        waitUntil(promise);
      },
    },
  },
});
Token Security

Tokens expire after 1 hour by default. Configure with resetPasswordTokenExpiresIn (in seconds):

export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    resetPasswordTokenExpiresIn: 60 * 30, // 30 minutes
  },
});

Tokens are single-use — deleted immediately after successful reset.

Session Revocation

Enable revokeSessionsOnPasswordReset to invalidate all existing sessions on password reset:

export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    revokeSessionsOnPasswordReset: true,
  },
});
Password Requirements

Password length limits (configurable):

export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    minPasswordLength: 12,
    maxPasswordLength: 256,
  },
});

Sending the Password Reset

Call requestPasswordReset to send the reset link. Triggers the sendResetPassword function from your config.

const data = await auth.api.requestPasswordReset({
  body: {
    email: "john.doe@example.com", // required
    redirectTo: "https://example.com/reset-password",
  },
});

Or authClient:

const { data, error } = await authClient.requestPasswordReset({
  email: "john.doe@example.com", // required
  redirectTo: "https://example.com/reset-password",
});

Note: While the email is required, we also recommend configuring the redirectTo for a smoother user experience.

Password Hashing

Default: scrypt (Node.js native, no external dependencies).

Custom Hashing Algorithm

To use Argon2id or another algorithm, provide custom hash and verify functions:

import { betterAuth } from "better-auth";
import { hash, verify, type Options } from "@node-rs/argon2";

const argon2Options: Options = {
  memoryCost: 65536, // 64 MiB
  timeCost: 3, // 3 iterations
  parallelism: 4, // 4 parallel lanes
  outputLen: 32, // 32 byte output
  algorithm: 2, // Argon2id variant
};

export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    password: {
      hash: (password) => hash(password, argon2Options),
      verify: ({ password, hash: storedHash }) =>
        verify(storedHash, password, argon2Options),
    },
  },
});

Note: If you switch hashing algorithms on an existing system, users with passwords hashed using the old algorithm won't be able to sign in. Plan a migration strategy if needed.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.