import type { EmailConfig, EmailUserConfig } from '@auth/core/providers/email'; import { generateRandomString, RandomReader } from '@oslojs/crypto/random'; import { alphabet } from 'oslo/crypto'; import { UseSend } from 'usesend-js'; export default function UseSendProvider(config: EmailUserConfig): EmailConfig { return { id: 'usesend', type: 'email', name: 'UseSend', from: process.env.USESEND_FROM_EMAIL ?? 'noreply@example.com', maxAge: 24 * 60 * 60, // 24 hours async generateVerificationToken() { const random: RandomReader = { read(bytes) { crypto.getRandomValues(bytes); }, }; return generateRandomString(random, alphabet('0-9'), 6); }, async sendVerificationRequest(params) { const { identifier: to, provider, url, token } = params; // Derive a display name from the site URL, fallback to 'App' const siteUrl = process.env.USESEND_FROM_EMAIL ?? ''; const appName = siteUrl.split('@')[1]?.split('.')[0] ?? 'App'; const useSend = new UseSend( process.env.USESEND_API_KEY!, process.env.USESEND_URL!, ); // For password reset, we want to send the code, not the magic link const isPasswordReset = url.includes('reset') || provider.id?.includes('reset'); const result = await useSend.emails.send({ from: provider.from!, to: [to], subject: isPasswordReset ? `Reset your password - ${appName}` : `Sign in to ${appName}`, text: isPasswordReset ? `Your password reset code is ${token}` : `Your sign in code is ${token}`, html: isPasswordReset ? `

Password Reset Request

You requested a password reset. Your reset code is:

${token}

This code expires in 1 hour.

If you didn't request this, please ignore this email.

` : `

Your Sign In Code

Your verification code is:

${token}

This code expires in 24 hours.

`, }); if (result.error) { throw new Error('UseSend error: ' + JSON.stringify(result.error)); } }, options: config, }; } // Create specific instances for password reset and email verification export const UseSendOTPPasswordReset = UseSendProvider({ id: 'usesend-otp-password-reset', apiKey: process.env.USESEND_API_KEY, maxAge: 60 * 60, // 1 hour }); export const UseSendOTP = UseSendProvider({ id: 'usesend-otp', apiKey: process.env.USESEND_API_KEY, maxAge: 60 * 20, // 20 minutes });