diff --git a/README.md b/README.md index 74917c8..c5211ce 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,9 @@ releases, comentarios y relaciones entre tickets, **en tiempo real**. docker compose up -d --build # web en http://localhost:8080 ``` -Para entrar hace falta un cliente OAuth de Pireon en `.env` (`PIREON_CLIENT_ID` y `PIREON_CLIENT_SECRET`, ver -[Autenticación](docs/05-autenticacion.md#registrar-taskstream-como-cliente-en-pireon)). Para desarrollar: +Para entrar hacen falta los clientes OAuth de Pireon en `.env`: uno `authorization_code` (`PIREON_CLIENT_ID` / +`_SECRET`, «Entrar con Pireon») y uno `password` (`PIREON_PASSWORD_CLIENT_ID` / `_SECRET`, email y contraseña). Ver +[Autenticación](docs/05-autenticacion.md#registrar-taskstream-como-cliente-en-pireon). Para desarrollar: ```sh npm install # @pi/ui necesita el token del Nexus de Pireon en ~/.npmrc diff --git a/docs/05-autenticacion.md b/docs/05-autenticacion.md index 3972185..af01926 100644 --- a/docs/05-autenticacion.md +++ b/docs/05-autenticacion.md @@ -64,17 +64,45 @@ Con un token tuyo de Pireon (scope `account:write`), `POST https://oauth.pireon. `https://api.taskstream.pireon.dev/api/docs/oauth2-redirect.html` (ver [API REST](03-api.md#33-rest-con-openapi-para-otras-apps)) - → `PIREON_CLIENT_ID` y `PIREON_CLIENT_SECRET`. + → `PIREON_CLIENT_ID` y `PIREON_CLIENT_SECRET`. Al ser confidencial, **el secret es obligatorio**: sin él Pireon + rechaza el canje del código (ver la tabla de errores más abajo). 2. **Cliente para email y contraseña**: `{"name": "TaskStream (password)", "grant_type": "password"}` → `PIREON_PASSWORD_CLIENT_ID` y `PIREON_PASSWORD_CLIENT_SECRET`. -Ponlos en `.env` (o en el entorno del contenedor; en Dokploy, en _Environment_) y reinicia la API. +Pireon muestra el secret (`plain_secret`) **una sola vez**, en la respuesta de alta. Si se pierde, se genera otro con +`POST https://oauth.pireon.dev/api/clients/{client}/rotate-secret` (el anterior sigue valiendo 48 h). + +Ponlos en `.env` (o en el entorno del contenedor; en Dokploy, en _Environment_) y reinicia la API; en Docker/Dokploy, +**recrea** el contenedor (redesplegar), porque un reinicio no relee el entorno. + +En producción: + +| Servicio | URL | Redirect URIs registradas en el cliente `authorization_code` | +| ---------- | ----------------------------------- | ----------------------------------------------------------------- | +| Web | `https://taskstream.pireon.dev` | `https://taskstream.pireon.dev/auth/callback` | +| API (REST) | `https://api.taskstream.pireon.dev` | `https://api.taskstream.pireon.dev/api/docs/oauth2-redirect.html` | `GET /api/auth/config` le dice a la web qué formas de entrar hay: `clientId` del cliente `authorization_code` (o `null`: la web oculta «Entrar con Pireon») y `passwordGrant`. Devuelve `null` si no hay ningún cliente; en ese caso el login muestra el aviso y no deja entrar. +### Si el login falla + +La API reenvía el error de Pireon con su `hint` entre paréntesis (lo que de verdad falla) y lo registra en su log como +`Pireon rejected for client : … (hint: …)`. + +| Error | Causa | Solución | +| ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| El login dice «Inicio de sesión no configurado» | `GET /api/auth/config` devuelve `null`: no hay ningún cliente en el entorno de la API | Define `PIREON_CLIENT_ID` y/o `PIREON_PASSWORD_CLIENT_ID` (con sus secrets) y recrea el contenedor | +| `unauthorized_client`: _not authorized to use this authorization grant type_ | El cliente no es del tipo que pide el flujo (p. ej. uno `password` en `PIREON_CLIENT_ID`) | Un cliente `authorization_code` en `PIREON_CLIENT_ID` y uno `password` en `PIREON_PASSWORD_CLIENT_ID` | +| `invalid_request` … _(Check the `client_secret` parameter)_ | El cliente es confidencial y la API no envía secret: la variable está vacía o no llega | Pon el secret en `PIREON_CLIENT_SECRET` (o `PIREON_PASSWORD_CLIENT_SECRET`) y redespliega | +| `invalid_client`: _Client authentication failed_ | El secret llega pero no es el de ese cliente | Revisa que id y secret sean del mismo cliente; si no lo tienes, rótalo | +| `invalid_request` … _(Invalid redirect URI)_ | La redirect URI del canje no es la de la autorización | Regístrala exactamente igual en el cliente (esquema, dominio y ruta, sin barra final) | +| `invalid_grant`: _Authorization code has expired / has been revoked_ | El código caducó o ya se usó (p. ej. al recargar `/auth/callback`) | Vuelve a «Entrar con Pireon» | +| `The user credentials were incorrect.` | Email o contraseña de Pireon incorrectos | — | +| Errores `404 Cannot GET/POST /api/…` intermitentes a través de la web | Otro `api` en la red compartida de Dokploy recibe parte de las peticiones | Ya resuelto con alias únicos (`task-stream-api`…), ver [Despliegue](07-despliegue.md#nombres-únicos-en-la-red) | + ### Sesión en la web - La sesión (`accessToken`, `refreshToken`, caducidad) se guarda en `localStorage` y se restaura al arrancar. diff --git a/docs/06-desarrollo.md b/docs/06-desarrollo.md index 4b71f41..68f40db 100644 --- a/docs/06-desarrollo.md +++ b/docs/06-desarrollo.md @@ -92,3 +92,4 @@ exporta facades, una página tampoco puede tocar un store ni despachar eventos p | La API no ve un evento nuevo al deserializar | La clase del evento no tiene `@AutowiredEvent` o no se importa | | Un componente de `@pi/ui` lanza `Unable to find icon` | Falta registrar ese icono en `libs/web/shared/ui/src/lib/icons.ts` | | Tablas antiguas (`projects`, `issues`, `outbox`) en tu Postgres local | Restos de una versión anterior sin event sourcing; `docker compose down -v` empieza de cero | +| El login con Pireon falla (`unauthorized_client`, `client_secret`…) | Configuración de los clientes OAuth: ver [Si el login falla](05-autenticacion.md#si-el-login-falla) | diff --git a/docs/README.md b/docs/README.md index fd879e2..d803d51 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,4 +22,5 @@ Cada librería de `libs/` tiene además su propio `README.md` con su responsabil docker compose up -d --build # web en http://localhost:8080 ``` -Para entrar hace falta un cliente OAuth de Pireon en `.env` (ver [Autenticación](05-autenticacion.md#registrar-taskstream-como-cliente-en-pireon)). +Para entrar hacen falta dos clientes OAuth de Pireon en `.env` (`authorization_code` y `password`, ver +[Autenticación](05-autenticacion.md#registrar-taskstream-como-cliente-en-pireon)). diff --git a/docs/TaskStream-Documentacion.docx b/docs/TaskStream-Documentacion.docx index e5ae207..d3692d4 100644 Binary files a/docs/TaskStream-Documentacion.docx and b/docs/TaskStream-Documentacion.docx differ diff --git a/docs/TaskStream-Documentacion.pdf b/docs/TaskStream-Documentacion.pdf index 5ba5bad..fdf8a3a 100644 Binary files a/docs/TaskStream-Documentacion.pdf and b/docs/TaskStream-Documentacion.pdf differ