Una app de autenticación nunca recibe el código que te muestra. Cuando activas la verificación en dos pasos, el sitio te entrega un secreto — normalmente 20 bytes aleatorios, escondidos dentro de ese código QR — y tu app se queda con su propia copia. A partir de ahí los dos lados hacen la misma aritmética: toman la hora Unix actual, la dividen entre 30 y descartan el resto, pasan ese número por HMAC usando el secreto compartido como clave y luego comprimen la salida hasta dejarla en seis dígitos. Tu teléfono muestra su respuesta, el servidor calcula la suya, y las dos coinciden porque coincidían las entradas. No se intercambia nada, y por eso la app sigue funcionando dentro de un avión.
Qué hay en realidad dentro del código QR
Texto, y no mucho. El código QR es una forma compacta de escribir una sola URL:
otpauth://totp/Example:you@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example
La única parte que importa es secret. El resto es etiquetado: el issuer y el nombre de la cuenta existen para que tu app pueda mostrar "Example" junto al código en lugar de una fila de dígitos anónimos. El formato admite tres parámetros más, algorithm, digits y period, y varias apps muy usadas ignoran los tres y suponen SHA-1, seis dígitos y treinta segundos, diga lo que diga el enlace.
El secreto se escribe en base32: las letras de la A a la Z y los dígitos del 2 al 7. No hay 0, ni 1, ni 8, precisamente porque son los caracteres que la gente confunde con la O, la I y la B al copiar una clave a mano. Además no distingue mayúsculas de minúsculas, cosa que base64 sí hace. El precio es la longitud: 20 bytes necesitan 32 caracteres en base32 donde base64 habría usado 27.
Los cuatro pasos que convierten el reloj en seis dígitos
- Contar los intervalos. Toma el timestamp Unix, los segundos transcurridos desde el 1 de enero de 1970, divídelo entre 30 y tira la fracción. En 2026 eso es un número algo por debajo de 60 millones, que sube dos veces por minuto en todo reloj bien puesto en hora.
- Aplicarle un hash con el secreto. El contador se escribe como ocho bytes y se pasa por HMAC-SHA-1, con el secreto como clave. HMAC es un hash con clave: la misma entrada bajo otra clave produce una salida sin ninguna relación, y la salida no dice nada sobre la clave. Si ese paso deja demasiado sin explicar, qué es un hash y qué no lo es cubre el terreno que hay debajo de este paso.
- Truncar, de una forma rara. HMAC-SHA-1 da 20 bytes, demasiados para escribirlos. Los últimos cuatro bits de ese resultado se leen como un número del 0 al 15, y ese número se usa como desplazamiento dentro del propio resultado: se toman cuatro bytes desde ahí y se descarta el bit más alto. Descartar ese bit no tiene nada que ver con la seguridad. Existe para que las implementaciones que tratan el valor como con signo y las que lo tratan como sin signo lleguen al mismo número.
- Quedarse con el resto. Lo que queda es un número de 31 bits. Módulo un millón, se convierte en los seis dígitos que lees. Aproximadamente uno de cada diez códigos cae por debajo de 100000, y por eso las apps rellenan con ceros a la izquierda.
Nada de esto es nuevo. El original basado en contador, HOTP, es el RFC 4226 de diciembre de 2005, escrito para funcionar en un token de llavero con casi nada de procesador. TOTP es el RFC 6238 de mayo de 2011: la misma construcción con el reloj en el lugar del contador. El paso de truncado parece extraño porque es un fósil de aquel hardware.
Por qué 30 segundos
Es un término medio, y bastante arbitrario. Un intervalo más corto hace que un código robado valga menos, pero también significa que quien escribe despacio en el teclado del teléfono ve cambiar el número a mitad de camino. Treinta segundos son suficientes para leer un código en una pantalla y escribirlo en otra, y lo bastante poco como para que un código que quedó en una captura de pantalla suela estar vencido antes de que alguien lo encuentre.
Solo hay un millón de códigos posibles de seis dígitos, así que no es la longitud lo que hace difícil vencer a TOTP. Lo que frena a quien prueba códigos a ciegas es que el servidor cuente los intentos fallidos, no la aritmética. Un formulario de inicio de sesión que deja a alguien probar códigos toda la tarde está roto, sin importar cómo se produzcan los números.
Por qué un código que escribiste tarde todavía funciona
Porque el servidor normalmente comprueba más de un intervalo. Los relojes se desvían, y sin eso un teléfono tres segundos atrasado fallaría uno de cada dos inicios de sesión. La mayoría de las implementaciones aceptan el intervalo anterior y el siguiente junto al actual, una ventana de unos 90 segundos. Algunas son más estrictas, y por eso el mismo código tardío pasa sin problema en un sitio y es rechazado en otro.
Por qué tus códigos dejan de funcionar de repente
Solo hay unas pocas causas.
- El reloj del dispositivo se desvió. La causa más común, de lejos. Un teléfono con dos minutos de desfase produce códigos que están mal en todas partes a la vez, lo que se parece exactamente a un secreto corrupto.
- El algoritmo no coincide. Si el enlace de configuración pedía SHA-256 y la app usó SHA-1 sin decir nada, cada código es un código TOTP válido para los parámetros equivocados.
- El secreto se copió mal. Una O mayúscula escrita donde base32 no tiene cero, o una l minúscula haciendo de 1. Un solo carácter equivocado cambia todos los códigos.
- Es la entrada equivocada. Dos cuentas del mismo servicio una al lado de la otra en una lista larga.
Distinguir unas de otras es más rápido con una segunda opinión. Si todavía tienes la semilla original, pégala en un generador de códigos TOTP en otra computadora y compara los dos códigos en el mismo instante. Si los códigos son distintos, uno de los dos relojes está mal. El mismo código en los dos, y aun así rechazado por el sitio, apunta al algoritmo, al número de dígitos o a la entrada equivocada — no a la semilla.
Qué arregla TOTP y qué no
Acaba con el credential stuffing. Una contraseña filtrada en la brecha de otra persona, o reutilizada en una docena de sitios, deja de ser suficiente por sí sola. Para ese trabajo TOTP es excelente y casi gratis.
No detiene el phishing. Un código escrito en una página falsa convincente vale treinta segundos para quien lo esté retransmitiendo al sitio real, y los kits de phishing hacen exactamente eso, en vivo, mientras la víctima espera a que cargue la página. Las passkeys y las llaves de seguridad de hardware cierran ese agujero porque el acceso queda atado al origen del sitio; un número de seis dígitos que puedes leer en voz alta no puede estarlo.
Tampoco repara una contraseña mala. El servidor tiene que guardar tu semilla en un formato que pueda volver a leer, porque necesita recalcular tus códigos, así que una brecha de esa base de datos le entrega a un atacante un generador de códigos permanente, no un hash de contraseña que todavía haya que romper. La contraseña es entonces lo único que queda en pie. Si has estado tratando el segundo factor como permiso para conservar un primero débil, cuánto tardarían en descifrar tu contraseña son cinco minutos bien invertidos.
La semilla es lo que hay que respaldar
Perder el teléfono es menos catastrófico de lo que la gente espera, siempre que la semilla haya sobrevivido en algún lado. En TOTP no hay ningún paso de emparejamiento ni identidad de dispositivo en ninguna parte: dos dispositivos con el mismo secreto muestran el mismo código, porque quien tiene el secreto eres tú en lo que al protocolo respecta. Eso es también la advertencia: una foto del código QR de configuración en tu galería es un segundo factor que funciona para cualquiera que entre en tus fotos.
Guarda los códigos de recuperación que el sitio te ofrece al configurarlo, y tenlos en algún lugar que no sea el teléfono. Son la única vía de vuelta una vez que la semilla ha desaparecido, y los servicios manejan mal su ausencia, normalmente pidiéndote una foto de tu pasaporte.
Una advertencia honesta sobre hacer cualquiera de estas cosas en una pestaña del navegador. Una página que puede calcular tus códigos tiene tu semilla mientras está abierta, y pegar una semilla en uso en cualquier parte es una decisión, no un reflejo. El generador de aquí no escribe nada en el almacenamiento, no pone ninguna cookie, no mete nada en la URL y olvida el secreto al recargar — pero existe para probar una implementación, confirmar que un respaldo sigue sirviendo o entrar una vez cuando el teléfono está en otro lado. No es una app de autenticación, y tampoco puede leer un código QR: no lleva cámara ni decodificador, así que necesitas la semilla en texto que los sitios esconden detrás del enlace "¿no puedes escanear el código?".
Cuando necesitas comprobar una semilla ahora mismo — después de una migración, o cuando el teléfono con la app no está en la habitación — el generador de códigos TOTP convierte un secreto en base32 o un enlace otpauth completo en el código actual y los segundos que le quedan, sin que el secreto salga de la página. Trátalo como un diagnóstico y no como el lugar donde guardar tus cuentas. Y como un segundo factor solo compra tiempo para el primero, los argumentos a favor de una frase de contraseña frente a una contraseña son la otra mitad de este problema, sobre todo si el sitio que guarda tu semilla es el que sufre la brecha.
Preguntas frecuentes
¿Cómo genera códigos una app de autenticación sin internet?
No necesita conexión porque no se envía nada. La app y el servidor tienen el mismo secreto y cada uno calcula un código a partir de la hora actual, así que los números coinciden sin haberse intercambiado nunca. La única entrada compartida es el reloj, y por eso un teléfono sin conexión sigue funcionando pero uno con la hora mal no.
¿Por qué mi código de autenticación aparece como inválido?
Casi siempre por un reloj que se ha desviado más de un minuto, ya que la hora es la mitad del cálculo. Las otras causas son un secreto copiado con un carácter equivocado, una app que usa SHA-1 donde el sitio esperaba SHA-256, o simplemente la entrada equivocada en una lista larga. Corrige primero la hora del teléfono, antes de dar por hecho que la configuración está rota.
¿Pueden dos teléfonos mostrar el mismo código 2FA?
Sí. TOTP no tiene noción de dispositivo, así que cualquier cantidad de apps con el mismo secreto produce códigos idénticos en el mismo instante. Así es como la gente mantiene un dispositivo de respaldo, y también es la razón de que una foto del código QR de configuración sea tan sensible como la propia contraseña.
¿Es más segura una app de autenticación que los códigos por SMS?
Sí, por una razón concreta: el código nunca viaja, así que no hay nada que interceptar ni un número de teléfono que secuestrar mediante un SIM swap. Las dos son igual de vulnerables a una página de phishing que retransmita tu código al sitio real en tiempo real. Solo las passkeys o una llave de seguridad de hardware cierran esa brecha, porque atan el acceso a la dirección del sitio.
¿Qué pasa si pierdo el teléfono con mi app de autenticación?
Pierdes el acceso a todas las cuentas cuyo secreto existía solo en ese teléfono. Los códigos de recuperación guardados al configurarla son la vía normal de vuelta, y un respaldo de la propia semilla también sirve. Sin ninguno de los dos, te queda la recuperación manual de cuenta que ofrezca el servicio, que suele significar documentos de identidad y una espera.
Última actualización 19 de septiembre de 2026