Better Auth e Resend: autenticazione che uno sviluppatore solo riesce davvero a rilasciare
- auth
- better-auth
- resend
Autenticazione self-hosted con Better Auth, email transazionali con Resend. Nessun vendor lock-in, nessun costo nascosto, e una configurazione che un agente AI può riprodurre da un file markdown.
L'autenticazione è la parte di ogni progetto che sembra semplice finché non sei tre giorni dentro a fare il debug di loop di redirect OAuth a mezzanotte. Il mio requisito per NearYou era chiaro: accesso con email e password, login sociale con Google, verifica email, reset della password, due fattori in futuro e zero costi mensili per un servizio che potrebbe restare inattivo per settimane durante lo sviluppo iniziale. Better Auth più Resend è quello stack. Ti mostro esattamente come si incastra.
Perché Better Auth
Better Auth è una libreria di autenticazione self-hosted per l'ecosistema JavaScript. La installi come pacchetto, la colleghi al database esistente tramite un adapter, e possiedi l'intera tabella di sessioni e utenti. Nessun servizio di autenticazione esterno chiama casa. Nessun prezzo per utente attivo mensile che ti sorprende quando un post diventa virale. Nessuna migrazione dal vendor quando i prezzi cambiano.
Il set di funzionalità è pronto per la produzione sin dall'inizio: email e password, provider sociali (Google, Facebook, GitHub e altri), verifica email, reset della password, autenticazione a due fattori via TOTP e un adapter Prisma che genera automaticamente i modelli di schema necessari. Le sessioni sono memorizzate nel tuo database. La rotazione dei token è gestita. La libreria client include hook tipizzati per React e altri framework, così non scrivi la tua logica useSession.
L'unica cosa che Better Auth non include è la consegna delle email. Espone degli hook, tu colleghi il trasporto. Questa è la separazione corretta: la logica di autenticazione rimane in Better Auth, la consegna va a un servizio costruito esattamente per quel compito.

Perché Resend per le email transazionali
Resend è un servizio di email transazionale orientato agli sviluppatori. Il tier gratuito offre 3.000 email al mese e 100 al giorno, il che copre comodamente qualsiasi progetto nelle fasi iniziali. I prezzi a pagamento sono abbastanza bassi da non doverli considerare finché non hai una base utenti reale. L'API è una singola chiamata di funzione. Nessuna configurazione SMTP, nessun incubo di intestazioni di autenticazione, nessun XML da nessuna parte.
I requisiti sono minimi ma non negoziabili. Hai bisogno di un dominio di invio che controlli. Devi aggiungere tre record DNS a quel dominio: un record SPF, una chiave DKIM che Resend genera per te e una policy DMARC. Hai bisogno di una chiave API dalla dashboard di Resend. E hai bisogno di un indirizzo from chiaro e coerente che corrisponda al tuo dominio verificato. Una volta che questi sono a posto, la consegna funziona e il placement nella casella di posta è solido.
Configurare la chiamata Resend
L'SDK Node di Resend è un piccolo wrapper attorno alla loro API REST. Installalo con npm install resend, esporta una funzione tipizzata per tipo di email e chiamala dai tuoi hook di Better Auth. La disciplina chiave: non costruire mai stringhe HTML inline nella configurazione auth. Inseriscile in un modulo dedicato lib/email.ts così è testabile e sostituibile.
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function sendVerificationEmail(to: string, url: string) {
await resend.emails.send({
from: 'NearYou <noreply@mail.nearyou.app>',
to,
subject: 'Verify your email address',
html:
'<p>Click the link below to verify your account:</p>' +
'<p><a href="' + url + '">' + url + '</a></p>',
});
}Tieni RESEND_API_KEY nel tuo file .env e non committarla mai. L'indirizzo from deve corrispondere esattamente al tuo dominio verificato. Se cambi il dominio di invio in seguito, aggiorna questa stringa e riverifica nella dashboard di Resend. La funzione è deliberatamente semplice: una chiamata di invio, una superficie di errore. Aggiungi una gestione degli errori e logging appropriati prima di andare in produzione.
Collegare Better Auth per usarla
La configurazione di Better Auth vive in un unico file auth.ts nella radice del progetto o in lib/. Il blocco emailVerification è dove passi la tua funzione di invio. L'hook riceve l'oggetto utente e un URL di verifica pre-costruito. Inoltri entrambi al tuo wrapper Resend. L'URL è firmato e limitato nel tempo da Better Auth internamente, quindi non gestisci tu stesso i token.
import { betterAuth } from 'better-auth';
import { prismaAdapter } from 'better-auth/adapters/prisma';
import { prisma } from './lib/prisma';
import { sendVerificationEmail } from './lib/email';
export const auth = betterAuth({
database: prismaAdapter(prisma, { provider: 'mysql' }),
emailAndPassword: {
enabled: true,
requireEmailVerification: true,
},
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
},
},
emailVerification: {
sendOnSignUp: true,
autoSignInAfterVerification: true,
sendVerificationEmail: async ({ user, url }) => {
await sendVerificationEmail(user.email, url);
},
},
});Il flag requireEmailVerification: true blocca il login finché l'email non è confermata. autoSignInAfterVerification: true significa che l'utente atterra nell'app immediatamente dopo aver cliccato il link nella sua casella di posta, nessun secondo passaggio di login. Questa combinazione ti dà un flusso di onboarding pulito con codice minimo.
- Reset password: aggiungi
sendResetPasswordal bloccoemailAndPassword, stesso pattern dell'hook di verifica. - Provider sociali: imposta
google.clientIdegoogle.clientSecretdall'ambiente. Better Auth gestisce automaticamente la route di callback OAuth. - Due fattori: aggiungi
import { twoFactor } from "better-auth/plugins"e includilo nell'arrayplugins. Better Auth include la logica TOTP. - Scadenza sessione: imposta
session.expiresInesession.updateAgeper controllare la durata dei token e quando si aggiornano automaticamente.
Requisiti DNS: la parte che ti blocca
La deliverability delle email vive e muore con il DNS. Resend non invierà da un dominio non verificato. Anche se bypassi questo controllo in qualche modo, le email finiscono nello spam senza l'allineamento SPF e DKIM. Questo è l'unico passaggio che ha un vero periodo di attesa: le modifiche DNS possono richiedere fino a 48 ore per propagarsi globalmente, anche se in pratica di solito è meno di un'ora con i registrar moderni.
I tre record che ti servono sul tuo sottodominio di invio: SPF dice ai server riceventi quali host sono autorizzati a inviare per il tuo dominio. DKIM allega una firma crittografica ai messaggi in uscita così i destinatari possono verificare che non siano stati manomessi. DMARC dice ai server riceventi cosa fare quando i controlli SPF o DKIM falliscono. Resend ti mostra i valori esatti da incollare nel tuo provider DNS dopo aver aggiunto il dominio.

Persistere la configurazione in un file di memoria markdown
Uso Claude Code come agente AI di programmazione su NearYou. L'agente scrive la configurazione auth, collega gli hook email, aggiorna i file di ambiente e fa il debug dei problemi di consegna. Perché questo funzioni in modo affidabile tra le sessioni, l'agente ha bisogno di una memoria persistente della configurazione email esatta: quale dominio è verificato, qual è l'indirizzo from, quali record DNS sono in atto e quali sono i nomi delle variabili d'ambiente.
Senza un file di memoria, l'agente deve chiedere, inferire o indovinare ogni volta che inizia una nuova sessione. Potrebbe usare l'indirizzo from sbagliato, fare riferimento a un dominio non verificato, o collegare l'hook a una variabile d'ambiente con un nome diverso da quello che è effettivamente in .env. Questi sono piccoli errori che costano tempo reale di debug.
La soluzione è una sezione breve e precisa nel AGENTS.md del progetto (o un .claude/email.md dedicato se il progetto è grande). Tieni il dominio di invio, l'indirizzo from, la checklist dei record DNS e le note di collegamento degli hook lì. L'agente legge questo file all'avvio della sessione e opera la configurazione email correttamente al primo tentativo, ogni volta.
## Auth + Email (Better Auth + Resend)
Sending domain: mail.nearyou.app
From address: noreply@mail.nearyou.app
Resend API key: env var RESEND_API_KEY
### DNS records required on mail.nearyou.app
- SPF: TXT "v=spf1 include:amazonses.com ~all"
- DKIM: TXT resend._domainkey <value from Resend dashboard>
- DMARC: TXT _dmarc "v=DMARC1; p=quarantine; rua=mailto:dmarc@nearyou.app"
### Email hooks wired in auth.ts
- emailVerification.sendVerificationEmail -> sendVerificationEmail()
- emailAndPassword.sendResetPassword -> sendPasswordResetEmail()
### Gotchas
- Resend requires the from domain to be verified before any email sends.
- DNS propagation can take up to 48h; verify in the Resend dashboard.
- Always set autoSignInAfterVerification: true so the UX is not broken post-verify.
- Never hardcode the from address; keep it in this file so the agent reads it.Questo file è la differenza tra un agente che configura con sicurezza il tuo stack email e uno che ti fa tre domande prima di scrivere una singola riga. Non è documentazione per gli esseri umani. È un documento di contesto compatto per un sistema che non riesce a vedere la tua dashboard Resend, i tuoi record DNS o il tuo file .env. Ogni riga guadagna il suo posto prevenendo un errore reale.
Lo stack completo in produzione
Su NearYou, Better Auth e Resend sono in produzione sin dai primi utenti beta. Il flusso auth: registrazione con email e password o Google, ricezione di un'email di verifica inviata tramite Resend in pochi secondi, click sul link, atterraggio nell'app. Il reset della password usa lo stesso wrapper Resend. Due fattori via TOTP è collegato ma opzionale per gli utenti. L'intera superficie auth è self-hosted, nessuna dipendenza da vendor oltre Resend per la consegna.
Il costo operativo è trascurabile. Il tier gratuito di Resend gestisce la base utenti attuale con margine. Quando supererà il limite gratuito, il costo per email è abbastanza basso da restare un arrotondamento nel budget infrastrutturale. Better Auth non ha alcun costo per utente. Confronta con i prezzi di Auth0 o Clerk in scala e l'aritmetica non è nemmeno vicina.
La migliore configurazione auth è quella che possiedi, capisci e puoi debuggare alle 2 di notte senza aprire un ticket di supporto al vendor.
Se stai costruendo un nuovo progetto JavaScript o TypeScript e hai bisogno di autenticazione, inizia qui. Installa Better Auth, collegalo al tuo database Prisma esistente, aggiungi il wrapper Resend, inserisci i record DNS e compila il tuo AGENTS.md. Avrai un sistema di autenticazione funzionante e pronto per la produzione in mezza giornata, e non ci penserai per il prossimo anno.