blackmistcode's picture
Add files using upload-large-folder tool
71b8eb2 verified
|
Raw
History Blame Contribute Delete
5.45 kB
# Auth — Guía de uso
Login con email + password. El backend emite un JWT (HS256, default 1h) que viaja en `Authorization: Bearer <token>`. No hay registro público en esta fase: los usuarios se crean vía el seeder. **No hay roles**`requireAuth` solo valida que el usuario esté logueado y activo, para que pueda mantener sus preferencias.
## 1. Variables de entorno
Copiar `backend/.env.example` a `backend/.env` y rellenar:
| Variable | Default | Notas |
|---|---|---|
| `NODE_ENV` | `development` | `development` \| `test` \| `production` |
| `PORT` | `7860` | Puerto del backend (HF Spaces requiere 7860) |
| `DATABASE_URL` | `file:./polysignal.db` | Path SQLite **relativo a `prisma/schema.prisma`** |
| `JWT_SECRET` | — (obligatorio) | Mínimo 32 chars. Generar con `openssl rand -hex 48` |
| `JWT_EXPIRES_IN` | `1h` | Formato `jsonwebtoken` (`1h`, `15m`, `7d`, ...) |
| `BCRYPT_ROUNDS` | `10` | Entre 4 y 15 |
| `CORS_ORIGIN` | `http://localhost:5173` | Origen del frontend en dev |
| `LOG_LEVEL` | `info` | `trace`/`debug`/`info`/`warn`/`error`/`fatal` |
> Si el `.env` falta una variable obligatoria o un valor es inválido, el backend imprime el error y aborta el arranque (validación con Zod en `src/config.js`).
## 2. Primer arranque
Desde `backend/`:
```bash
npm install # instala deps
npm run db:migrate -- --name init_auth # solo la primera vez (ya hecho)
npm run db:seed # crea los 2 usuarios de prueba
npm run dev # arranca en http://localhost:7860
```
Para inspeccionar la DB en una UI:
```bash
npm run db:studio
```
## 3. Usuarios de prueba
Sembrados por `prisma/seed.js` (idempotente, se puede re-ejecutar):
| Email | Password |
|---|---|
| `admin@polysignal.test` | `Admin123!` |
| `user@polysignal.test` | `User123!` |
## 4. Endpoints
### `GET /api/v1/health`
Sanity check. Respuesta:
```json
{ "ok": true, "data": { "status": "up" } }
```
### `POST /api/v1/auth/login`
Body:
```json
{ "email": "admin@polysignal.test", "password": "Admin123!" }
```
Respuesta `200`:
```json
{
"ok": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiJ9...",
"user": { "id": 1, "email": "admin@polysignal.test" }
}
}
```
Errores:
| HTTP | code | cuándo |
|---|---|---|
| `400` | `VALIDATION_ERROR` | Email inválido o password < 8 chars |
| `401` | `INVALID_CREDENTIALS` | Email no existe, usuario desactivado, o password incorrecta |
| `429` | `TOO_MANY_REQUESTS` | Más de 5 intentos en 15 min desde la misma IP |
### `GET /api/v1/auth/me`
Requiere header `Authorization: Bearer <token>`. Respuesta `200`:
```json
{
"ok": true,
"data": {
"user": {
"id": 1,
"email": "admin@polysignal.test",
"isActive": true,
"createdAt": "2026-05-16T07:11:43.000Z"
}
}
}
```
Errores:
| HTTP | code | cuándo |
|---|---|---|
| `401` | `UNAUTHORIZED` | Sin header, token mal formado, expirado, manipulado, o usuario desactivado |
## 5. Ejemplos con `curl`
```bash
# 1) Login y guardar token en variable
TOKEN=$(curl -s -X POST http://localhost:7860/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"admin@polysignal.test","password":"Admin123!"}' \
| jq -r '.data.token')
# 2) Llamar a /me con el token
curl -s http://localhost:7860/api/v1/auth/me \
-H "Authorization: Bearer $TOKEN" | jq
```
## 6. Login desde el frontend (referencia)
El JWT es opaco para el front: basta con guardarlo (sessionStorage o estado en memoria) y enviarlo en cada request protegido.
```js
const res = await fetch('/api/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
const json = await res.json();
if (!json.ok) throw new Error(json.error.code);
const { token, user } = json.data;
// guardar token y user
// requests autenticados
fetch('/api/v1/auth/me', { headers: { Authorization: `Bearer ${token}` } });
```
> En dev, Vite proxea `/api/*` al backend (`localhost:7860`); no hace falta CORS si va por el proxy, pero ya está configurado por si el front llama directo.
## 7. Cómo proteger nuevos endpoints
```js
import { requireAuth } from '../middlewares/requireAuth.js';
router.get('/positions', requireAuth, controller.list);
```
Dentro del controller, `req.user` ya está disponible con `{ id, email, isActive, createdAt }` — suficiente para filtrar datos del usuario logueado (ej. sus preferencias, posiciones, watchlist).
## 8. Rotar `JWT_SECRET`
Genera uno nuevo y reemplaza el valor de `JWT_SECRET` en `backend/.env`:
```bash
openssl rand -hex 48
```
Al cambiar el secreto, todos los tokens emitidos previamente quedan invalidados (los clientes deben volver a hacer login).
## 9. Notas técnicas
- **Hashing:** `bcryptjs` (puro JS, sin compilación nativa — más portable a HF Spaces) con coste `BCRYPT_ROUNDS` (default 10).
- **JWT:** algoritmo `HS256`, claim `sub = user.id`, `email`, `iat`, `exp`.
- **Rate limit en `/auth/login`:** `express-rate-limit`, 5 intentos / 15 min / IP.
- **Validación de body:** zod schema en `src/auth/auth.validators.js`.
- **Errores formateados:** todas las respuestas siguen `{ ok, data }` o `{ ok:false, error:{ code, message, details? } }` vía `src/utils/apiResponse.js` y el middleware `errorHandler`.
- **Prisma:** singleton en `src/utils/prisma.js` para no abrir conexiones de más con `node --watch`.