Cargando…

Esto está tardando más de lo esperado.

Volver al centro de ayuda

Verifica el correo y el teléfono

Cómo viajan los códigos de un solo uso, quién los envía y los campos que los piden.

Una persona demuestra que un correo o un número de teléfono es suyo escribiendo un código que el kit envió ahí. Esta guía cubre cuándo ocurre, qué necesita cada canal en .env, cómo es el código y cómo poner esos mismos campos verificados en tus propios formularios.

Cuándo se pide un código

Momento Canal Condición
Registro, campo de correo Correo Siempre. El formulario recibe la dirección sólo cuando el código se confirma.
Registro, campo de teléfono SMS o llamada AUTH_ENABLE_VALIDATION=true. Apagado, el campo no tiene el enlace "Verificar ahora".
Inicio de sesión de un paso con correo sin verificar Correo AUTH_APPROACH es CreationValidation o LoginValidation, y AUTH_ENABLE_VALIDATION=true.
Inicio de sesión de dos pasos, paso uno, correo sin verificar Correo Siempre.
Perfil, al cambiar el correo Correo Siempre. El perfil conserva la nueva dirección sólo después del código.
Perfil, al cambiar el teléfono SMS o llamada Siempre.

No se envía nada cuando la dirección o el número ya pertenece a otra cuenta: el campo muestra el error de unicidad en su lugar.

El código

  • Los códigos por correo tienen diez caracteres, letras y dígitos, y distinguen mayúsculas. El asunto es "Validación de correo electrónico: " seguido del nombre de tu aplicación, y el cuerpo es un mensaje corto con el código.
  • Los códigos por teléfono tienen cuatro dígitos. El mensaje dice "Tu app - Tu código de verificación es: 1234".

Cada solicitud genera un código nuevo, y cada reenvío reemplaza al anterior. El código vive en el estado de la pantalla que lo pidió: no tiene caducidad propia y desaparece con esa pantalla, así que recargar la página empieza de cero. Debe escribirse exacto; un valor equivocado responde "El código de verificación es incorrecto".

Bajo el campo del código corre una cuenta regresiva de treinta segundos: "¿No recibiste el código? 27s". Al terminar aparece el enlace "Reenviar código"; en la pantalla del teléfono, "Reenviar SMS" y "Recibir una llamada". La cuenta regresiva es el único freno: no hay límite de intentos contra un código.

Los códigos por correo y el mailer

Los códigos por correo pasan por el sistema de correo de Laravel, de forma síncrona, con el mailable App\Mail\Auth\ValidateEmail. El primer envío usa MAIL_MAILER. Cada reenvío avanza al siguiente mailer de mail_fallbacks en config/auth.php, que viene así:

'mail_fallbacks' => [
    'mailgun',
],

Con la configuración por omisión una persona puede pedir el código dos veces: una por MAIL_MAILER, otra por Mailgun. Un tercer intento ya no encuentra mailer y muestra "No pudimos enviar el código de verificación. Por favor, intenta con otro correo electrónico". Agrega nombres al arreglo para permitir más reenvíos; el mismo nombre puede repetirse. El mailer que finalmente entregó queda registrado en el extra_data de la cuenta bajo mail_driver_used.

Los mailers y sus variables son los de config/mail.php: smtp, mailgun, ses, postmark, resend, log, y failover, que .env.example selecciona y que intenta Mailgun y luego SES. Sus credenciales y cómo elegir uno están en /help/email-and-sms-delivery.

Los códigos por teléfono y el proveedor

AUTH_VALIDATION_PROVIDER elige quién lleva el código al teléfono.

aws, el valor por omisión: Amazon SNS

El código sale como SMS transaccional por Amazon SNS con estas credenciales:

AUTH_VALIDATION_PROVIDER=aws
AWS_ACCESS_KEY_ID=your-aws-access-key-id
AWS_SECRET_ACCESS_KEY=your-aws-secret-access-key
AWS_DEFAULT_REGION=us-west-1

La región vuelve a us-west-1 cuando la variable falta. Son las mismas llaves que usan el mailer ses y el disco S3, así que un solo usuario IAM con permisos de SNS, SES y S3 cubre los tres. SNS sólo envía mensajes de texto: el diálogo del teléfono envía el SMS en cuanto abre y no hay opción de llamada. El número se envía tal como la persona lo escribió, por eso el campo pide incluir el código de país.

telnyx: Telnyx Verify

AUTH_VALIDATION_PROVIDER=telnyx
TELNYX_API_KEY=your-telnyx-api-key
TELNYX_VERIFY_PROFILE_ID=your-telnyx-verify-profile-id

TELNYX_TOKEN se acepta como nombre antiguo de la llave. Crea un perfil de Verify en el portal de Telnyx y pega su id; el kit le pasa su propio código de cuatro dígitos al perfil, así que el SMS y la llamada llevan el código que la pantalla espera. Con Telnyx el diálogo pregunta primero "Elige cómo quieres recibir el código de verificación" con dos botones, "Enviar SMS" y "Recibir una llamada", y la llamada sigue disponible bajo la cuenta regresiva como alternativa. El número se normaliza a formato internacional antes de la petición, y un número que no se puede normalizar se rechaza.

Con cualquiera de los dos proveedores, cuando falta una llave o el perfil, o el proveedor responde con error, la persona ve el diálogo "No se pudo enviar el código. No pudimos enviar el código de verificación a su teléfono. Por favor, inténtelo de nuevo." y el error se reporta a tu log. Dar de alta cada proveedor, y los SMS que el kit envía fuera de la verificación, se cubren en /help/email-and-sms-delivery.

Lo que ve la persona

En el registro y en el inicio de sesión la tarjeta completa se reemplaza: el título "Por favor confirma tu correo electrónico" o "Por favor confirma tu teléfono", una línea "Se envió un código a tu correo electrónico", un campo "Código de validación", un botón "Confirmar correo electrónico" o "Confirmar código" y la cuenta regresiva. Al confirmar el código, el flujo retoma donde se detuvo: la cuenta se crea, o la sesión abre.

En el perfil, y dentro del registro para el teléfono, la verificación abre como una ventana modal: "Verificar nuevo correo electrónico" o "Verificar nuevo teléfono", el mismo campo, botón y cuenta regresiva. Al confirmar, la ventana cierra, el campo muestra el nuevo valor con una insignia verde "Verificado", y el perfil lo guarda de inmediato.

Los componentes <x-email-input> y <x-phone-input>

Ambos son componentes Blade que envuelven un campo con una insignia de verificación y el enlace "Verificar ahora", y ambos son los campos que el propio kit usa en el registro y en el perfil. Colócalos en cualquier formulario Livewire:

<x-email-input :label="__('Email address')" wire:model.live="user.email" />

<x-phone-input
    :label="__('Phone (Include country code)')"
    wire:model.live="user.phone"
    :validation-required="true"
    :verified-at="$user->phone_verified_at"
    dispatch-context="profile"
/>

wire:model, o wire:model.live, es el único atributo obligatorio: nombra la propiedad de tu componente que recibe el valor verificado. label y placeholder llegan al campo; cualquier otro atributo se acepta y se ignora.

Atributo Componente Qué hace
validation-required teléfono true muestra el enlace "Verificar ahora". Por omisión false: la insignia se muestra, pero el enlace nunca aparece y el campo dice "Teléfono no válido" bajo cualquier valor sin verificar.
verified-at teléfono La marca de tiempo que decide si el valor actual empieza como "Verificado". Pasa el phone_verified_at del modelo, o null cuando el valor en pantalla difiere del guardado.
dispatch-context teléfono Una cadena que vuelve en el evento identity-verified para que tu listener sepa qué formulario preguntó. Por omisión, la ruta del wire:model.

El componente de correo no tiene esos atributos. Su enlace "Verificar ahora" siempre se muestra, empieza como "Verificado" cuando la propiedad enlazada ya tiene un valor, y el contexto de su evento es siempre la ruta del wire:model, user.email en el ejemplo.

Comportamiento compartido por ambos:

  • Bajo el campo, una insignia dice "Verificado" en verde o "No verificado" en ámbar. Escribir un valor distinto del inicial la cambia a "No verificado".
  • "Verificar ahora" aparece cuando el valor está bien formado: un correo válido, o un teléfono con al menos once dígitos. Antes de eso se muestra en su lugar "Formato de correo electrónico no válido" o "Teléfono no válido".
  • Antes de enviar, el componente revisa que ninguna otra cuenta tenga el valor y muestra el error de unicidad si la hay.
  • Tu propiedad enlazada recibe el valor sólo cuando el código se confirma. Mientras la persona escribe, conserva su valor anterior, o pasa a null en el correo en cuanto cambia el valor inicial. Por eso una regla required sobre esa propiedad es lo que vuelve obligatoria la verificación; así lo exige el formulario de registro.

Reaccionar a una verificación

Cuando un código se confirma, la ventana modal despacha identity-verified con type, email o phone, value, verified_at y context; el evento del teléfono lleva además column, la ruta del wire:model. Escúchalo cuando necesites guardar la marca de tiempo:

use Livewire\Attributes\On;

#[On('identity-verified')]
public function onIdentityVerified($data)
{
    if ($data['context'] !== 'profile') {
        return;
    }

    if ($data['type'] === 'phone') {
        $this->user->phone = $data['value'];
        $this->user->phone_verified_at = $data['verified_at'];
        $this->user->save();
    }
}

Revisa context primero: la ventana modal es compartida y una página puede tener varios de estos campos. El contexto del correo es su ruta de wire:model, así que un listener para él compara contra 'user.email' y no contra un nombre que tú elijas.

Desarrollo local

El kit no registra los códigos en ningún lado, así que dales un lugar donde caer:

  • Correo: pon MAIL_MAILER=log. El mensaje completo, código incluido, se escribe en storage/logs/laravel.log, o en el canal de MAIL_LOG_CHANNEL. Recuerda que un reenvío avanza a mail_fallbacks, que apunta a Mailgun: sin credenciales de Mailgun el reenvío falla con error, así que vacía el arreglo en local o pide el código una sola vez. Un capturador SMTP local como Mailpit funciona igual con MAIL_MAILER=smtp.
  • Teléfono: no hay atajo local. Los SMS y las llamadas pasan por el proveedor real, así que usa credenciales reales y tu propio número, o desarrolla con una identidad de correo y deja el teléfono para una pasada posterior.
  • La suite de pruebas corre con MAIL_MAILER=array, definido en phpunit.xml, así que nada sale de la máquina durante las pruebas.