Skip to content

imansi-auth-react

Hooks de autenticación para React: login, registro, 2FA, OAuth, recuperación de contraseña y gestión de sesiones. Sin componentes visuales. Compatible con imansi-auth-node.

npm versionLicense: MIT


¿Qué es?

imansi-auth-react es la librería de hooks de autenticación del ecosistema Imansi. No incluye componentes visuales: solo la lógica y el estado. Vos armás la UI como quieras.

Está diseñada para funcionar con imansi-auth-node en el backend.

Se recomienda usar ambas librerías juntas. Comparten el mismo contrato HTTP y los mismos nombres en español.

┌─────────────────────┐         ┌─────────────────────┐
│  imansi-auth-react  │ ──────► │  imansi-auth-node   │
│   (tu frontend)     │  HTTP   │    (tu backend)     │
└─────────────────────┘         └─────────────────────┘

Características

  • Hooks específicos para cada flujo: login, registro, 2FA, recuperación y más
  • Sin componentes visuales: máxima libertad para diseñar tu UI
  • OAuth con GitHub y Google listo para enchufar
  • Sesión persistente con cookies httpOnly
  • Refresh tokens automáticos sin que el usuario note nada
  • Protección de rutas (<ProtegerRuta> y <RedirigirSiAutenticado>)
  • 100% configurable desde props y configuración
  • JavaScript puro. Sin TypeScript, sin sorpresas
  • Cero dependencias de UI. Vos decidís cómo se ve todo

Instalación

bash
npm install imansi-auth-react

Requiere React 18+ y react-router-dom 6+:

bash
npm install react react-dom react-router-dom

Para el backend (recomendado):

bash
npm install imansi-auth-node

Uso rápido

1. Envolvé tu app con <ProveedorAutenticacion>

jsx
// src/App.jsx
import { BrowserRouter } from 'react-router-dom';
import { ProveedorAutenticacion } from 'imansi-auth-react';

const configuracion = {
  urlBase: 'http://localhost:3000',
  modoAlmacenamiento: 'httpOnly',
  incluirCredenciales: true,
  rutaLogin: '/login',
  rutaTrasLogin: '/panel',
  rutaTrasRegistro: '/panel',
};

export default function App() {
  return (
    <BrowserRouter>
      <ProveedorAutenticacion configuracion={configuracion}>
        {/* Tu app */}
      </ProveedorAutenticacion>
    </BrowserRouter>
  );
}

2. Armá tu propio login con useLogin

jsx
import { useState } from 'react';
import { useNavigate, Link } from 'react-router-dom';
import { useLogin } from 'imansi-auth-react';

export function MiLogin() {
  const { iniciarSesion, error, requiereVerificacion2fa } = useLogin();
  const navegar = useNavigate();

  const [correo, setCorreo] = useState('');
  const [contrasena, setContrasena] = useState('');
  const [enviando, setEnviando] = useState(false);

  if (requiereVerificacion2fa) {
    return <MiVerificacion2FA />;
  }

  async function manejar(evento) {
    evento.preventDefault();
    setEnviando(true);
    const resultado = await iniciarSesion({ correo, contrasena });
    setEnviando(false);

    if (!resultado.ok) {
      alert(resultado.error.mensaje);
      return;
    }
    if (resultado.requiere2fa) return;
    navegar('/panel');
  }

  return (
    <form onSubmit={manejar}>
      <h1>Iniciar sesión</h1>
      <input
        type="email"
        placeholder="Correo"
        value={correo}
        onChange={(e) => setCorreo(e.target.value)}
      />
      <input
        type="password"
        placeholder="Contraseña"
        value={contrasena}
        onChange={(e) => setContrasena(e.target.value)}
      />
      {error && <p style={{ color: 'red' }}>{error.mensaje}</p>}
      <button type="submit" disabled={enviando}>
        {enviando ? 'Entrando...' : 'Entrar'}
      </button>
      <Link to="/recuperar">¿Olvidaste tu contraseña?</Link>
    </form>
  );
}

3. Protegé tus rutas

jsx
import { ProtegerRuta, RedirigirSiAutenticado } from 'imansi-auth-react';

<Routes>
  <Route
    path="/login"
    element={
      <RedirigirSiAutenticado>
        <MiLogin />
      </RedirigirSiAutenticado>
    }
  />
  <Route
    path="/panel"
    element={
      <ProtegerRuta cargando={<p>Cargando...</p>}>
        <MiPanel />
      </ProtegerRuta>
    }
  />
</Routes>

Hooks disponibles

useLogin()

Login con email y contraseña.

jsx
const { iniciarSesion, cargando, error, requiereVerificacion2fa } = useLogin();

await iniciarSesion({ correo, contrasena });
// → { ok: true, usuario } | { ok: true, requiere2fa: true } | { ok: false, error }

useRegistro()

Registro con email, contraseña y nombre opcional.

jsx
const { registrarUsuario, error } = useRegistro();
await registrarUsuario({ nombre, correo, contrasena });

useVerificar2FA()

Verifica el código de 2FA.

jsx
const { verificarDosFactores, reenviarDosFactores, error } = useVerificar2FA();
await verificarDosFactores('353251');
await reenviarDosFactores();

useRecuperacion()

Solicitar y restablecer contraseña.

jsx
const { solicitarRecuperacion, restablecerContrasena } = useRecuperacion();

await solicitarRecuperacion('usuario@email.com');
await restablecerContrasena({ token, contrasena: 'nueva123' });

useCambioContrasena()

Cambiar contraseña estando logueado.

jsx
const { cambiarContrasena, usuario } = useCambioContrasena();

if (usuario?.tieneContrasena) {
  await cambiarContrasena({ contrasenaActual, contrasenaNueva });
}

useEditarPerfil()

Editar el nombre del usuario.

jsx
const { editarPerfil, usuario } = useEditarPerfil();
await editarPerfil({ nombre: 'Ivan Mansilla' });

useSesiones()

Listar y revocar sesiones activas.

jsx
const { listarSesiones, revocarSesion } = useSesiones();

const sesiones = await listarSesiones();
await revocarSesion(sesiones[0].id);

useOAuth()

Iniciar el flujo OAuth.

jsx
const { iniciarOAuth, proveedores, textos } = useOAuth();

<button onClick={() => iniciarOAuth('github')}>
  Continuar con GitHub
</button>

useAutenticacion()

Hook completo con todo. Útil si preferís un solo hook.

jsx
const {
  usuario, token, sesion, autenticado, cargando, error,
  iniciarSesion, registrarUsuario, cerrarSesion, recargarUsuario,
  idPendiente2fa, requiereVerificacion2fa,
  verificarDosFactores, reenviarDosFactores, cancelar2fa,
  listarSesiones, revocarSesion,
  solicitarRecuperacion, restablecerContrasena,
  cambiarContrasena, editarPerfil,
  configuracion,
} = useAutenticacion();

Protección de rutas

<ProtegerRuta>

Bloquea rutas privadas. Si no hay sesión, redirige al login.

PropTipoDescripción
redireccionstringRuta a la que redirigir (default: configuracion.rutaLogin)
cargandoReactNodeQué mostrar mientras se valida la sesión

<RedirigirSiAutenticado>

Para rutas públicas (login, registro). Si ya hay sesión, redirige.

PropTipoDescripción
redireccionstringRuta a la que redirigir (default: configuracion.rutaTrasLogin)
cargandoReactNodeQué mostrar mientras se valida

Configuración completa

jsx
const configuracion = {
  urlBase: 'http://localhost:3000',
  modoAlmacenamiento: 'httpOnly',
  incluirCredenciales: true,
  rutaLogin: '/login',
  rutaTrasLogin: '/panel',
  rutaTrasRegistro: '/panel',
  rutaTrasRestablecer: '/login',

  oauth: {
    proveedores: ['github', 'google'],
    textos: {
      github: 'Entrar con GitHub',
      google: 'Entrar con Google',
      o: 'o también',
    },
  },
};

Seguridad

  • Cookies httpOnly: el token nunca es accesible desde JavaScript
  • Refresh tokens automáticos: el access token dura poco y se renueva solo
  • Detección automática de 401: si el access token expira, el hook lo renueva sin que el usuario note nada
  • Deduplicación de refrescos concurrentes: si varias peticiones reciben 401 al mismo tiempo, se hace un solo refresh
  • Sin almacenamiento inseguro por defecto: no usamos localStorage a menos que lo pidas explícitamente

Próximos pasos

Hecho con ❤️ en Argentina