imansi-auth-react
v0.1.3
Published
Hooks de autenticación para React: login, registro, 2FA, OAuth (GitHub y Google), recuperación de contraseña y gestión de sesiones. Sin componentes visuales. Compatible con imansi-auth-node.
Maintainers
Readme
imansi-auth-react
Hooks de autenticación para React: login, registro, verificación en dos pasos (2FA), OAuth (GitHub y Google), recuperación de contraseña, cambio de contraseña, edición de perfil y gestión de sesiones.
Sin componentes visuales. Solo la lógica. Vos armás la UI como quieras.
Compatible con imansi-auth-node — el servidor de autenticación completo para Node.js.
Parte del ecosistema Imansi — autenticación moderna para tus apps.
⚠️ Recomendación importante
Esta librería está diseñada para funcionar con imansi-auth-node, el servidor de autenticación que la complementa.
Se recomienda fuertemente usar ambas librerías juntas. El frontend (imansi-auth-react) y el backend (imansi-auth-node) están diseñados para trabajar en conjunto sin configuración adicional. Comparten el mismo contrato HTTP y los mismos nombres en español.
┌─────────────────────┐ ┌─────────────────────┐
│ imansi-auth-react │ ──────► │ imansi-auth-node │
│ (tu frontend) │ HTTP │ (tu backend) │
└─────────────────────┘ └─────────────────────┘También funciona con cualquier backend que respete los endpoints documentados en la sección Endpoints esperados.
✨ 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
npm install imansi-auth-reactRequiere React 18+ y react-router-dom 6+ (van como peerDependencies):
npm install react react-dom react-router-domPara el backend (recomendado):
npm install imansi-auth-node🚀 Uso rápido
1. Envolvé tu app con <ProveedorAutenticacion>
// 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
// src/paginas/MiLogin.jsx
import { useState } from "react";
import { useNavigate, Link } from "react-router-dom";
import { useLogin } from "imansi-auth-react";
export function MiLogin() {
const { iniciarSesion, requiereVerificacion2fa, error } = useLogin();
const navegar = useNavigate();
const [correo, setCorreo] = useState("");
const [contrasena, setContrasena] = useState("");
const [enviando, setEnviando] = useState(false);
// Si el backend pide 2FA, mostramos nuestra pantalla de verificación.
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>
<Link to="/registro">Crear cuenta</Link>
</form>
);
}3. Protegé tus rutas
// src/App.jsx (continuación)
import { Routes, Route } from "react-router-dom";
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>Listo. Con eso ya tenés el flujo básico funcionando.
🪝 Hooks disponibles
Todos los hooks se importan desde imansi-auth-react.
useLogin()
Login con email y contraseña.
const {
iniciarSesion,
cargando,
error,
requiereVerificacion2fa,
idPendiente2fa,
cancelar2fa,
autenticado
} = useLogin();
await iniciarSesion({ correo, contrasena });
// → { ok: true, usuario } | { ok: true, requiere2fa: true } | { ok: false, error }useRegistro()
Registro con email, contraseña y nombre opcional.
const { registrarUsuario, error, requiereVerificacion2fa } = useRegistro();
await registrarUsuario({ nombre, correo, contrasena });
// → { ok: true, usuario } | { ok: true, requiere2fa: true } | { ok: false, error }useVerificar2FA()
Verifica el código de 2FA.
const {
verificarDosFactores,
reenviarDosFactores,
cancelar2fa,
requiereVerificacion2fa,
error
} = useVerificar2FA();
await verificarDosFactores("353251");
// → { ok: true, usuario } | { ok: false, error }
await reenviarDosFactores();
// → { ok: true } | { ok: false, error }useRecuperacion()
Solicitar y restablecer contraseña.
const { solicitarRecuperacion, restablecerContrasena, error } = useRecuperacion();
// Paso 1: pedir el link
await solicitarRecuperacion("[email protected]");
// → { ok: true, mensaje }
// Paso 2: con el token del link
await restablecerContrasena({ token, contrasena: "nueva123" });
// → { ok: true, mensaje } | { ok: false, error }useCambioContrasena()
Cambiar la contraseña estando logueado.
const { cambiarContrasena, usuario, error, autenticado } = useCambioContrasena();
// Verificar que el usuario tenga contraseña (no sea solo-OAuth)
if (usuario?.tieneContrasena) {
await cambiarContrasena({ contrasenaActual, contrasenaNueva });
// → { ok: true, mensaje } | { ok: false, error }
}Importante: los usuarios que se registraron solo con OAuth (GitHub/Google) tienen usuario.tieneContrasena === false. No pueden cambiar la contraseña porque no tienen.
useEditarPerfil()
Editar el nombre del usuario logueado.
const { editarPerfil, usuario, error } = useEditarPerfil();
await editarPerfil({ nombre: "Ivan Mansilla" });
// → { ok: true, usuario, mensaje } | { ok: false, error }useSesiones()
Listar y revocar sesiones activas.
const { listarSesiones, revocarSesion, error } = useSesiones();
const sesiones = await listarSesiones();
// → [{ id, dispositivo, ip, actual, creadoEn, ultimaActividad }, ...]
await revocarSesion(sesiones[0].id);
// → { ok: true } | { ok: false, error }useOAuth()
Iniciar el flujo OAuth con GitHub o Google.
const { iniciarOAuth, proveedores, textos } = useOAuth();
// proveedores → ["github", "google"] (los que configuraste)
<button onClick={() => iniciarOAuth("github")}>
Continuar con GitHub
</button>
// O con redirección específica:
<button onClick={() => iniciarOAuth("github", "/panel")}>
Continuar con GitHub
</button>Nota: iniciarOAuth redirige el navegador al backend. No es un fetch, es un window.location.href.
useAutenticacion()
Hook completo con todo. Útil si preferís un solo hook en lugar de los específicos.
const {
// Estado
usuario,
token,
sesion,
autenticado,
cargando,
error,
// Acciones
iniciarSesion,
registrarUsuario,
cerrarSesion,
recargarUsuario,
// 2FA
idPendiente2fa,
requiereVerificacion2fa,
verificarDosFactores,
reenviarDosFactores,
cancelar2fa,
// Sesiones
listarSesiones,
revocarSesion,
// Recuperación
solicitarRecuperacion,
restablecerContrasena,
// Cuenta
cambiarContrasena,
editarPerfil,
// Configuración efectiva
configuracion
} = useAutenticacion();🛡️ Protección de rutas
<ProtegerRuta>
Bloquea rutas privadas. Si no hay sesión, redirige al login.
import { ProtegerRuta } from "imansi-auth-react";
<Route
path="/panel"
element={
<ProtegerRuta cargando={<p>Cargando...</p>}>
<Panel />
</ProtegerRuta>
}
/>| Prop | Tipo | Descripción |
|---|---|---|
| redireccion | string | Ruta a la que redirigir si no hay sesión (por defecto configuracion.rutaLogin) |
| cargando | ReactNode | Qué mostrar mientras se valida la sesión inicial |
<RedirigirSiAutenticado>
Para rutas públicas (login, registro). Si ya hay sesión, redirige.
import { RedirigirSiAutenticado } from "imansi-auth-react";
<Route
path="/login"
element={
<RedirigirSiAutenticado>
<MiLogin />
</RedirigirSiAutenticado>
}
/>| Prop | Tipo | Descripción |
|---|---|---|
| redireccion | string | Ruta a la que redirigir si hay sesión (por defecto configuracion.rutaTrasLogin) |
| cargando | ReactNode | Qué mostrar mientras se valida la sesión |
📚 Ejemplos completos
Ejemplo 1: Registro con validación
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { useRegistro } from "imansi-auth-react";
export function MiRegistro() {
const { registrarUsuario, error, requiereVerificacion2fa } = useRegistro();
const navegar = useNavigate();
const [nombre, setNombre] = useState("");
const [correo, setCorreo] = useState("");
const [contrasena, setContrasena] = useState("");
const [contrasenaRepetir, setContrasenaRepetir] = useState("");
const [errorLocal, setErrorLocal] = useState(null);
if (requiereVerificacion2fa) {
return <MiVerificacion2FA />;
}
async function manejar(evento) {
evento.preventDefault();
setErrorLocal(null);
if (contrasena !== contrasenaRepetir) {
setErrorLocal("Las contraseñas no coinciden");
return;
}
if (contrasena.length < 6) {
setErrorLocal("La contraseña debe tener al menos 6 caracteres");
return;
}
const resultado = await registrarUsuario({ nombre, correo, contrasena });
if (!resultado.ok) {
setErrorLocal(resultado.error.mensaje);
return;
}
if (resultado.requiere2fa) return;
navegar("/panel");
}
return (
<form onSubmit={manejar}>
<h1>Crear cuenta</h1>
<input
placeholder="Nombre (opcional)"
value={nombre}
onChange={(e) => setNombre(e.target.value)}
/>
<input
type="email"
placeholder="Correo"
value={correo}
onChange={(e) => setCorreo(e.target.value)}
required
/>
<input
type="password"
placeholder="Contraseña"
value={contrasena}
onChange={(e) => setContrasena(e.target.value)}
required
/>
<input
type="password"
placeholder="Repetir contraseña"
value={contrasenaRepetir}
onChange={(e) => setContrasenaRepetir(e.target.value)}
required
/>
{(errorLocal || error) && (
<p style={{ color: "red" }}>{errorLocal || error.mensaje}</p>
)}
<button type="submit">Registrarme</button>
</form>
);
}Ejemplo 2: Verificación 2FA
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { useVerificar2FA } from "imansi-auth-react";
export function MiVerificacion2FA() {
const {
verificarDosFactores,
reenviarDosFactores,
cancelar2fa,
error
} = useVerificar2FA();
const navegar = useNavigate();
const [codigo, setCodigo] = useState("");
const [aviso, setAviso] = useState(null);
async function manejar(evento) {
evento.preventDefault();
const resultado = await verificarDosFactores(codigo);
if (!resultado.ok) {
return;
}
navegar("/panel");
}
async function reenviar() {
await reenviarDosFactores();
setAviso("Código reenviado. Revisá tu correo.");
}
function cancelar() {
cancelar2fa();
navegar("/login");
}
return (
<form onSubmit={manejar}>
<h1>Verificación en dos pasos</h1>
<p>Ingresá el código que enviamos a tu correo.</p>
<input
inputMode="numeric"
placeholder="Código de 6 dígitos"
value={codigo}
onChange={(e) => setCodigo(e.target.value)}
autoFocus
required
/>
{error && <p style={{ color: "red" }}>{error.mensaje}</p>}
{aviso && <p style={{ color: "green" }}>{aviso}</p>}
<button type="submit">Verificar</button>
<button type="button" onClick={reenviar}>Reenviar código</button>
<button type="button" onClick={cancelar}>Cancelar</button>
</form>
);
}Ejemplo 3: Recuperación de contraseña
Paso 1: solicitar
import { useState } from "react";
import { useRecuperacion } from "imansi-auth-react";
export function MiSolicitarRecuperacion() {
const { solicitarRecuperacion } = useRecuperacion();
const [correo, setCorreo] = useState("");
const [exito, setExito] = useState(false);
async function manejar(evento) {
evento.preventDefault();
await solicitarRecuperacion(correo);
setExito(true);
}
if (exito) {
return (
<p>
Si el correo está registrado, te enviamos un link para restablecer
tu contraseña. Revisá tu bandeja de entrada (y spam).
</p>
);
}
return (
<form onSubmit={manejar}>
<h1>Recuperar contraseña</h1>
<input
type="email"
placeholder="Tu correo"
value={correo}
onChange={(e) => setCorreo(e.target.value)}
required
/>
<button type="submit">Enviar link</button>
</form>
);
}Paso 2: restablecer
import { useState } from "react";
import { useSearchParams, useNavigate } from "react-router-dom";
import { useRecuperacion } from "imansi-auth-react";
export function MiRestablecer() {
const { restablecerContrasena, error } = useRecuperacion();
const navegar = useNavigate();
const [searchParams] = useSearchParams();
const token = searchParams.get("token");
const [contrasena, setContrasena] = useState("");
const [contrasenaRepetir, setContrasenaRepetir] = useState("");
const [errorLocal, setErrorLocal] = useState(null);
async function manejar(evento) {
evento.preventDefault();
setErrorLocal(null);
if (contrasena !== contrasenaRepetir) {
setErrorLocal("Las contraseñas no coinciden");
return;
}
if (contrasena.length < 6) {
setErrorLocal("La contraseña debe tener al menos 6 caracteres");
return;
}
const resultado = await restablecerContrasena({ token, contrasena });
if (resultado.ok) {
alert("Contraseña actualizada. Ya podés iniciar sesión.");
navegar("/login");
}
}
if (!token) {
return <p>El link no es válido. Pedí uno nuevo.</p>;
}
return (
<form onSubmit={manejar}>
<h1>Nueva contraseña</h1>
<input
type="password"
placeholder="Nueva contraseña"
value={contrasena}
onChange={(e) => setContrasena(e.target.value)}
required
/>
<input
type="password"
placeholder="Repetir contraseña"
value={contrasenaRepetir}
onChange={(e) => setContrasenaRepetir(e.target.value)}
required
/>
{(errorLocal || error) && (
<p style={{ color: "red" }}>{errorLocal || error.mensaje}</p>
)}
<button type="submit">Restablecer contraseña</button>
</form>
);
}Ejemplo 4: OAuth (GitHub + Google)
import { useOAuth } from "imansi-auth-react";
export function MisBotonesOAuth() {
const { iniciarOAuth, proveedores, textos } = useOAuth();
return (
<div>
{proveedores.includes("github") && (
<button onClick={() => iniciarOAuth("github")}>
{textos.github || "Continuar con GitHub"}
</button>
)}
{proveedores.includes("google") && (
<button onClick={() => iniciarOAuth("google")}>
{textos.google || "Continuar con Google"}
</button>
)}
</div>
);
}Requisitos:
- El backend debe tener configuradas las credenciales de GitHub/Google.
- El
urlBaseen la configuración debe apuntar al backend correcto. - La URL del callback en GitHub/Google debe ser
{urlBase}/auth/oauth/{proveedor}/callback.
Ejemplo 5: Mi cuenta (perfil + seguridad + sesiones)
import { useState, useEffect } from "react";
import {
useEditarPerfil,
useCambioContrasena,
useSesiones,
useAutenticacion
} from "imansi-auth-react";
export function MiCuenta() {
const { usuario, cerrarSesion } = useAutenticacion();
const { editarPerfil } = useEditarPerfil();
const { cambiarContrasena } = useCambioContrasena();
const { listarSesiones, revocarSesion } = useSesiones();
const [nombre, setNombre] = useState(usuario?.nombre || "");
const [sesiones, setSesiones] = useState([]);
useEffect(() => {
listarSesiones().then(setSesiones);
}, []);
async function guardarPerfil(evento) {
evento.preventDefault();
await editarPerfil({ nombre });
alert("Perfil actualizado");
}
async function revocar(sesionId) {
await revocarSesion(sesionId);
setSesiones(sesiones.filter((s) => s.id !== sesionId));
}
return (
<div>
<h1>Mi cuenta</h1>
{/* Perfil */}
<section>
<h2>Perfil</h2>
<form onSubmit={guardarPerfil}>
<input
value={nombre}
onChange={(e) => setNombre(e.target.value)}
/>
<button>Guardar</button>
</form>
</section>
{/* Cambiar contraseña (solo si tiene) */}
{usuario?.tieneContrasena && <MiCambiarContrasena />}
{/* Sesiones activas */}
<section>
<h2>Sesiones activas</h2>
{sesiones.map((s) => (
<div key={s.id}>
<span>{s.dispositivo || "Dispositivo desconocido"}</span>
{s.actual && <span> (esta sesión)</span>}
{!s.actual && (
<button onClick={() => revocar(s.id)}>Revocar</button>
)}
</div>
))}
</section>
<button onClick={cerrarSesion}>Cerrar sesión</button>
</div>
);
}
function MiCambiarContrasena() {
const { cambiarContrasena, error } = useCambioContrasena();
const [actual, setActual] = useState("");
const [nueva, setNueva] = useState("");
async function manejar(evento) {
evento.preventDefault();
const resultado = await cambiarContrasena({
contrasenaActual: actual,
contrasenaNueva: nueva
});
if (resultado.ok) alert("Contraseña cambiada");
}
return (
<section>
<h2>Cambiar contraseña</h2>
<form onSubmit={manejar}>
<input
type="password"
placeholder="Contraseña actual"
value={actual}
onChange={(e) => setActual(e.target.value)}
/>
<input
type="password"
placeholder="Nueva contraseña"
value={nueva}
onChange={(e) => setNueva(e.target.value)}
/>
{error && <p style={{ color: "red" }}>{error.mensaje}</p>}
<button>Cambiar</button>
</form>
</section>
);
}⚙️ Configuración
Todo se pasa al <ProveedorAutenticacion> mediante la prop configuracion:
<ProveedorAutenticacion configuracion={{
urlBase: "http://localhost:3000",
// ...
}}>Propiedades
| Propiedad | Por defecto | Descripción |
|---|---|---|
| urlBase | "" | URL del backend |
| endpoints | {...} | Rutas de los endpoints (raramente se cambian) |
| campos | {...} | Nombres de los campos enviados al backend |
| modoAlmacenamiento | "httpOnly" | "httpOnly", "cookie", "local", "sesion", "memoria" |
| incluirCredenciales | true | Enviar cookies en cada petición |
| rutaLogin | "/login" | Ruta del login para ProtegerRuta |
| rutaTrasLogin | "/" | Ruta tras login exitoso |
| rutaTrasRegistro | "/" | Ruta tras registro exitoso |
| rutaTrasRestablecer | "/login" | Ruta tras restablecer contraseña |
| oauth.proveedores | [] | Qué proveedores mostrar: ["github", "google"] |
| oauth.textos | {...} | Textos de los botones OAuth |
Ejemplo completo
const configuracion = {
urlBase: import.meta.env.VITE_URL_API_AUTENTICACION,
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"
}
}
};🔌 Endpoints esperados
imansi-auth-react se comunica con el backend a través de estos endpoints. Todos son manejados por imansi-auth-node por defecto.
| Método | Endpoint | Propósito |
|---|---|---|
| POST | /auth/registro | Crear usuario |
| POST | /auth/login | Iniciar sesión |
| POST | /auth/logout | Cerrar sesión |
| POST | /auth/refrescar | Renovar access token |
| GET | /auth/usuario | Obtener usuario actual |
| POST | /auth/verificar-2fa | Verificar código 2FA |
| POST | /auth/reenviar-2fa | Reenviar código 2FA |
| GET | /auth/sesiones | Listar sesiones |
| DELETE | /auth/sesiones/:id | Revocar sesión |
| POST | /auth/solicitar-recuperacion | Pedir link de recuperación |
| POST | /auth/restablecer-contrasena | Restablecer contraseña |
| POST | /auth/cambiar-contrasena | Cambiar contraseña (logueado) |
| PATCH | /auth/perfil | Editar perfil |
| GET | /auth/oauth/github | Iniciar OAuth GitHub |
| GET | /auth/oauth/google | Iniciar OAuth Google |
Si usás otro backend, tiene que respetar estos endpoints y los formatos de respuesta.
🔒 Seguridad
La librería está diseñada para máxima 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
localStoragea menos que lo pidas explícitamente. - OAuth sin tokens en la URL: el backend setea cookies httpOnly y redirige al frontend.
🌐 CORS
Si el frontend y el backend están en dominios distintos, el backend debe permitir CORS con credenciales:
Access-Control-Allow-Origin: https://tu-frontend.com
Access-Control-Allow-Credentials: true⚠️ No uses Access-Control-Allow-Origin: * con credenciales. Los navegadores lo rechazan.
imansi-auth-node ya maneja esto automáticamente si configuras URL_FRONTEND correctamente.
🌍 Multi-idioma
Los textos de la UI los manejás vos. La librería no impone ningún idioma.
Los correos que envía el backend (imansi-auth-node) soportan es, en y pt. Se configura en el correos.json del backend.
🧬 Ecosistema Imansi
imansi-auth-node— Servidor backend (Express + PostgreSQL). Recomendado.imansi-correos-node— 26 plantillas de correo.imansi-auth-react— Este paquete (frontend).
Todos comparten el mismo contrato HTTP y los mismos nombres en español.
📚 API pública
Contexto
ProveedorAutenticacion— Envuelve tu app.ContextoAutenticacion— Contexto puro (avanzado).
Hooks
useAutenticacion— Todo en uno.useLogin— Login.useRegistro— Registro.useVerificar2FA— Verificación 2FA.useRecuperacion— Recuperar y restablecer contraseña.useCambioContrasena— Cambiar contraseña.useEditarPerfil— Editar nombre.useSesiones— Sesiones activas.useOAuth— OAuth.
Protección de rutas
ProtegerRuta— Bloquea rutas privadas.RedirigirSiAutenticado— Redirige rutas públicas.
Servicios (uso avanzado sin hooks)
iniciarSesion,registrarUsuario,obtenerUsuariocerrarSesion,refrescarSesionverificarDosFactores,reenviarDosFactoreslistarSesiones,revocarSesionsolicitarRecuperacion,restablecerContrasenacambiarContrasena,editarPerfil
Utilidades
guardarSesion,obtenerSesion,eliminarSesionconfiguracionPorDefecto,crearConfiguracionnormalizarError
🛠️ Desarrollo
Clonar y probar localmente
git clone https://github.com/imansi-pro/imansi-auth-react.git
cd imansi-auth-react
npm install
npm run devScripts disponibles
| Script | Qué hace |
|---|---|
| npm run dev | Arranca el demo con Vite |
| npm run build | Compila la librería a dist/ |
| npm run preview | Previsualiza el build |
| npm run lint | Corre oxlint |
Estructura del proyecto
imansi-auth-react/
├── src/
│ ├── demo/ ← App de ejemplo (no se publica)
│ └── libreria/ ← Código del paquete
│ ├── almacenamiento/
│ ├── componentes/ ← (uso interno, no se exportan)
│ ├── configuracion/
│ ├── contexto/
│ ├── hooks/
│ │ ├── useAutenticacion.js
│ │ ├── useLogin.js
│ │ ├── useRegistro.js
│ │ ├── useVerificar2FA.js
│ │ ├── useRecuperacion.js
│ │ ├── useCambioContrasena.js
│ │ ├── useEditarPerfil.js
│ │ ├── useSesiones.js
│ │ └── useOAuth.js
│ ├── rutas/
│ ├── servicios/
│ ├── utilidades/
│ └── index.js
├── LICENSE
├── package.json
├── README.md
└── vite.config.js📄 Licencia
MIT © 2026 Ivan Mansilla
💬 Soporte
- Documentación: docs.imansi.pro
- Issues: github.com/imansi-pro/imansi-auth-react/issues
