Verificación de email con Firebase
Firebase Authentication permite interceptar los eventos de registro con funciones bloqueantes beforeCreate. Este tutorial añade la verificación de Mailbeam a ese hook para que los emails inválidos y desechables se bloqueen antes de crear el registro de usuario en Firebase.
Requisitos previos
- Un proyecto de Firebase con plan Blaze (necesario para Cloud Functions)
- La CLI de Firebase instalada
- Una clave de API de Mailbeam (regístrate gratis)
Preparación
firebase init functions
cd functions
npm install axiosDefine la clave de Mailbeam como variable de entorno de Firebase:
firebase functions:config:set mailbeam.key="mb_live_xxxxxxxxxxxxxxxxxxxx"Crea la función bloqueante
// functions/index.js
const functions = require("firebase-functions");
const { getAuth } = require("firebase-admin/auth");
const axios = require("axios");
// beforeCreate se ejecuta ANTES de escribir el usuario en Firebase Auth
exports.validateEmailBeforeCreate = functions.auth
.user()
.beforeCreate(async (user, context) => {
const email = user.email;
if (!email) return; // Sin email: otros proveedores, sáltalo
const apiKey = functions.config().mailbeam.key;
try {
const { data } = await axios.post(
"https://api.mailbeam.dev/v1/verify",
{ email },
{
headers: { Authorization: `Bearer ${apiKey}` },
timeout: 5000,
}
);
const { valid, score, reason } = data;
if (!valid || score < 60) {
const message =
reason === "disposable_domain"
? "Usa una dirección de email permanente, no una temporal."
: "Escribe una dirección de email válida y alcanzable.";
throw new functions.auth.HttpsError("invalid-argument", message);
}
} catch (err) {
// Si ya es nuestro HttpsError, relánzalo
if (err.code === "functions/invalid-argument") throw err;
// Si no: registra el error y falla en abierto
functions.logger.error("Ha fallado la verificación de Mailbeam", { error: err.message });
}
});Versión en TypeScript
// functions/src/index.ts
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import axios from "axios";
admin.initializeApp();
export const validateEmailBeforeCreate = functions.auth
.user()
.beforeCreate(async (user) => {
if (!user.email) return;
const apiKey = functions.config().mailbeam.key;
try {
const { data } = await axios.post<{
valid: boolean;
score: number;
reason: string | null;
}>(
"https://api.mailbeam.dev/v1/verify",
{ email: user.email },
{ headers: { Authorization: `Bearer ${apiKey}` }, timeout: 5000 }
);
if (!data.valid || data.score < 60) {
throw new functions.auth.HttpsError(
"invalid-argument",
data.reason === "disposable_domain"
? "Usa una dirección de email permanente."
: "Usa una dirección de email válida y alcanzable."
);
}
} catch (err: unknown) {
if ((err as { code?: string }).code === "functions/invalid-argument") throw err;
functions.logger.error("Error de Mailbeam", err);
}
});Despliegue
firebase deploy --only functionsPruebas
// Usa la Emulator Suite de Firebase para probar en local
firebase emulators:start
// Intenta crear un usuario con un email desechable desde el SDK de Firebase
const { createUserWithEmailAndPassword } = require("firebase/auth");
try {
await createUserWithEmailAndPassword(auth, "temp@mailinator.com", "password");
} catch (error) {
console.log(error.code); // "auth/invalid-argument"
console.log(error.message); // "Usa una dirección de email permanente."
}Buenas prácticas
- Usa
beforeCreate, noonCreate:beforeCreatese ejecuta antes de guardar el registro yonCreatedespués - Relanza siempre
functions.auth.HttpsErrory falla en abierto ante cualquier otro error - Usa
functions.logger.error, noconsole.error, para tener logs estructurados en Firebase