npm package: @kardoe/better-auth-aws-ses
Description: AWS SES email plugin for Better Auth - zero external dependencies, uses native Web Crypto API
Author: Quickback
Latest version: 1.0.1

# @kardoe/better-auth-aws-ses

AWS SES email plugin for [Better Auth](https://better-auth.com) - zero external dependencies, uses native Web Crypto API.

## Features

- **Zero Dependencies**: Uses native Web Crypto API for AWS SigV4 signing - works in Node.js, Cloudflare Workers, Deno, and Bun
- **Beautiful Email Templates**: Pre-built responsive HTML templates with dark mode support
- **Multiple Email Types**: Magic links, OTP codes, password reset, email verification, welcome emails, organization invitations, and account deletion
- **Combo Auth**: Combined magic link + OTP emails for better UX
- **Rate Limiting**: Built-in rate limiting support
- **Fully Typed**: Complete TypeScript support

## Installation

```bash
npm install @kardoe/better-auth-aws-ses
# or
pnpm add @kardoe/better-auth-aws-ses
# or
yarn add @kardoe/better-auth-aws-ses
```

## Quick Start

### Server Setup

```typescript
import { betterAuth } from "better-auth";
import { awsSESPlugin } from "@kardoe/better-auth-aws-ses";

export const auth = betterAuth({
  // ... your config
  plugins: [
    awsSESPlugin({
      // AWS SES Configuration
      region: process.env.AWS_REGION!,
      accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,

      // Email Settings
      fromEmail: "noreply@example.com",
      fromName: "My App",
      replyTo: "support@example.com",

      // App Settings
      appName: "My App",
      appUrl: "https://example.com",
      supportEmail: "support@example.com",

      // Optional: Company info for email footer
      companyName: "My Company",
      companyAddress: "123 Main St, City, Country",

      // Optional: Enable combo auth (magic link + OTP in same email)
      useComboAuthEmail: true,

      // Optional: Rate limiting
      rateLimit: {
        maxEmailsPerHour: 10,
        maxEmailsPerDay: 50,
      },
    }),
  ],
});
```

### Client Setup

```typescript
import { createAuthClient } from "better-auth/client";
import { awsSESClientPlugin } from "@kardoe/better-auth-aws-ses/client";

export const authClient = createAuthClient({
  plugins: [awsSESClientPlugin()],
});
```

## API Endpoints

The plugin adds the following API endpoints:

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/auth/ses/send-verification` | POST | Send email verification |
| `/api/auth/ses/send-password-reset` | POST | Send password reset email |
| `/api/auth/ses/send-magic-link` | POST | Send magic link email |
| `/api/auth/ses/send-otp` | POST | Send OTP code email |
| `/api/auth/ses/send-welcome` | POST | Send welcome email |
| `/api/auth/ses/send-organization-invitation` | POST | Send org invitation |
| `/api/auth/ses/send-email` | POST | Send custom email |
| `/api/auth/ses/status` | GET | Check email configuration status |

## Email Templates

All templates are responsive, support dark mode, and include plain text fallbacks.

### Available Templates

- **Email Verification** - For verifying new user email addresses
- **Password Reset** - For password reset requests with security warnings
- **Magic Link** - Passwordless sign-in links
- **Email OTP** - One-time password codes
- **Combo Auth** - Magic link + OTP in the same email
- **Welcome** - Welcome email for new users
- **Organization Invitation** - Inviting users to organizations
- **Delete Account** - Account deletion confirmation

### Customizing Templates

You can import and customize the templates:

```typescript
import { emailTemplates, baseEmailWrapper } from "@kardoe/better-auth-aws-ses/templates";

// Use a built-in template
const html = emailTemplates.magicLink.htmlTemplate({
  email: "user@example.com",
  url: "https://example.com/auth/verify?token=...",
  token: "abc123",
  appName: "My App",
  appUrl: "https://example.com",
});

// Or create a custom email with the base wrapper
const customHtml = baseEmailWrapper({
  appName: "My App",
  appUrl: "https://example.com",
  previewText: "Your custom email",
  content: `
    <h1>Custom Content</h1>
    <p>Your custom email content here...</p>
  `,
});
```

## AWS IAM Policy

Your IAM user/role needs the following permissions:

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource": "*"
    }
  ]
}
```

For production, restrict the resource to your verified identities:

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource": [
        "arn:aws:ses:us-east-1:123456789012:identity/example.com",
        "arn:aws:ses:us-east-1:123456789012:identity/noreply@example.com"
      ]
    }
  ]
}
```

## AWS SES Setup

1. **Verify your domain or email** in AWS SES Console
2. **Request production access** if you're in sandbox mode (sandbox only allows sending to verified emails)
3. **Create IAM credentials** with SES permissions
4. **Set environment variables**:

```bash
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
```

## Configuration Options

| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `region` | string | Yes | AWS region (e.g., "us-east-1") |
| `accessKeyId` | string | Yes | AWS access key ID |
| `secretAccessKey` | string | Yes | AWS secret access key |
| `fromEmail` | string | Yes | Sender email address |
| `fromName` | string | Yes | Sender display name |
| `appName` | string | Yes | Application name |
| `appUrl` | string | Yes | Application URL |
| `replyTo` | string | No | Reply-to email address |
| `supportEmail` | string | No | Support email for templates |
| `supportUrl` | string | No | Support URL for templates |
| `companyName` | string | No | Company name for footer |
| `companyAddress` | string | No | Company address for footer |
| `appTagline` | string | No | App tagline for welcome emails |
| `useComboAuthEmail` | boolean | No | Enable combo auth emails |
| `internalApiKey` | string | No | API key for internal calls |
| `rateLimit` | object | No | Rate limiting configuration |

## Utility Functions

The package exports utility functions for security:

```typescript
import {
  isValidEmail,
  escapeHtml,
  sanitizeUrl,
  sanitizeUserInput,
} from "@kardoe/better-auth-aws-ses";

// Validate email format
if (isValidEmail("user@example.com")) {
  // Valid email
}

// Escape HTML to prevent XSS
const safe = escapeHtml("<script>alert('xss')</script>");

// Sanitize URLs for email templates
const safeUrl = sanitizeUrl("https://example.com/callback");

// Sanitize user input for display
const safeName = sanitizeUserInput(userProvidedName, 100);
```

## TypeScript

Full TypeScript support with exported types:

```typescript
import type {
  SESConfig,
  AWSCredentials,
  SignatureParams,
} from "@kardoe/better-auth-aws-ses";

import type {
  EmailTemplateData,
  MagicLinkData,
  PasswordResetData,
  EmailVerificationData,
  EmailOTPData,
  ComboAuthData,
  WelcomeData,
  OrganizationInvitationData,
  DeleteAccountData,
} from "@kardoe/better-auth-aws-ses/templates";
```

## Runtime Support

This plugin works in:

- Node.js 18+
- Cloudflare Workers
- Deno
- Bun
- Any runtime with Web Crypto API support

## License

MIT