Buscar en la documentación

MFA

Política de MFA por rol, factores TOTP y códigos de recuperación.

Módulo auth3 min de lecturaVer en GitHub

Tres tablas sostienen la verificación en dos pasos: la política de cada rol, el factor de cada persona y sus códigos de recuperación. Además, users.mfa_grace_used cuenta los ingresos en que la persona pospuso configurarlo (ver users).

mfa_policies

Una fila por rol. Si un rol no tiene fila, no exige MFA.

ColumnaTipoRestriccionesDescripción
role_idSMALLINT UNSIGNEDPK, FK → roles.id, CASCADERol al que aplica
is_requiredBOOLEANNOT NULLSi el rol exige el MFA
grace_loginsTINYINT UNSIGNEDNOT NULLIngresos en que se puede posponer configurarlo. Al instalar: 1
created_at, updated_atTIMESTAMP

Con varios roles se aplica la regla más estricta: obligatorio si algún rol lo exige, con la gracia más corta.

user_mfa_factors

El segundo factor de cada persona. Hoy solo existe TOTP; la columna method deja lugar a otros (por ejemplo, passkeys) sin tocar users.

ColumnaTipoRestriccionesDescripción
idBIGINT UNSIGNEDPK
user_idBIGINT UNSIGNEDFK → users.id, CASCADEDueño del factor; se va con la cuenta
methodVARCHAR(20)NOT NULL, CHECK IN ('totp')Tipo de factor
secretTEXTNOT NULLSecreto TOTP cifrado con la clave de la aplicación; nunca en claro
confirmed_atTIMESTAMPNULLNull mientras la persona no lo confirma con su primer código
last_used_stepBIGINT UNSIGNEDNULLPaso de tiempo (30 s) del último código aceptado: uno igual o anterior se rechaza
created_at, updated_atTIMESTAMP
ÍndiceUso
(user_id, method) (único)Un factor por tipo y persona; es también la búsqueda de cada ingreso

user_recovery_codes

Los 8 códigos de recuperación de cada persona. Solo se guarda su hash.

ColumnaTipoRestriccionesDescripción
idBIGINT UNSIGNEDPK
user_idBIGINT UNSIGNEDFK → users.id, CASCADEDueño de los códigos
code_hashCHAR(64)NOT NULLSHA-256 del código normalizado (mayúsculas, con guion)
used_atTIMESTAMPNULLCuándo se usó; un código usado ya no sirve
created_atTIMESTAMPNOT NULLCuándo se generó el juego
ÍndiceUso
(user_id, code_hash) (único)Canjear un código: buscar por persona y hash

Ciclo de vida

  • Configurar: se crea el factor sin confirmar. Si la persona vuelve a empezar, el secreto pendiente se reemplaza.
  • Confirmar: en una misma transacción se marca confirmed_at y se guardan los 8 códigos.
  • Regenerar códigos: se borran los anteriores y se guardan 8 nuevos, en una transacción.
  • Desactivar: se borran el factor y sus códigos.
  • Borrar la cuenta: todo se va con ella (CASCADE).

Dónde está en el código