@kardoe/better-auth-aws-ses
v1.0.0
Published
AWS SES email plugin for Better Auth - zero external dependencies, uses native Web Crypto API
Maintainers
Readme
@kardoe/better-auth-aws-ses
AWS SES email plugin for Better Auth - 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
npm install @kardoe/better-auth-aws-ses
# or
pnpm add @kardoe/better-auth-aws-ses
# or
yarn add @kardoe/better-auth-aws-sesQuick Start
Server Setup
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: "[email protected]",
fromName: "My App",
replyTo: "[email protected]",
// App Settings
appName: "My App",
appUrl: "https://example.com",
supportEmail: "[email protected]",
// 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
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:
import { emailTemplates, baseEmailWrapper } from "@kardoe/better-auth-aws-ses/templates";
// Use a built-in template
const html = emailTemplates.magicLink.htmlTemplate({
email: "[email protected]",
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:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ses:SendEmail",
"ses:SendRawEmail"
],
"Resource": "*"
}
]
}For production, restrict the resource to your verified identities:
{
"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/[email protected]"
]
}
]
}AWS SES Setup
- Verify your domain or email in AWS SES Console
- Request production access if you're in sandbox mode (sandbox only allows sending to verified emails)
- Create IAM credentials with SES permissions
- Set environment variables:
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-keyConfiguration 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:
import {
isValidEmail,
escapeHtml,
sanitizeUrl,
sanitizeUserInput,
} from "@kardoe/better-auth-aws-ses";
// Validate email format
if (isValidEmail("[email protected]")) {
// 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:
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
