diff --git a/docs/configurar_msal.md b/docs/configurar_msal.md new file mode 100644 index 0000000..9424a97 --- /dev/null +++ b/docs/configurar_msal.md @@ -0,0 +1,88 @@ +# Configurar la aplicación de Microsoft Graph (MSAL) + +El proyecto lee y envía correo con Microsoft Graph usando una **aplicación registrada en Microsoft Entra ID** (antes Azure AD) y el flujo *client credentials*: no hay usuario interactivo, la aplicación se autentica sola con un `CLIENT_ID` y un `CLIENT_SECRET`. Este documento explica cómo obtener cada valor del `.env`. + +| Variable del `.env` | De dónde sale | +|---------------------|---------------| +| `CLIENT_ID` | *Application (client) ID* de la aplicación | +| `TENANT_ID` | *Directory (tenant) ID* de la aplicación | +| `CLIENT_SECRET` | **Value** de un *client secret* creado en esa misma aplicación | +| `EMAIL` | Dirección del buzón que se lee y desde el que se envía | + +> Los pasos describen el portal de Azure tal como suele verse; los nombres de los menús cambian de vez en cuando. + +## 1. Registrar la aplicación + +1. Entra a (o al portal de Azure) con una cuenta con permisos para registrar aplicaciones. +2. **Identity → Applications → App registrations → New registration**. +3. Nombre, por ejemplo `descarga-factura-transporte`. En *Supported account types* elige **Accounts in this organizational directory only** (un solo tenant). No hace falta *Redirect URI*. +4. En la página **Overview** de la aplicación copia: + - **Application (client) ID** → `CLIENT_ID` + - **Directory (tenant) ID** → `TENANT_ID` + +Los dos tienen que salir de la **misma** aplicación. Un `CLIENT_ID` de una aplicación con el `TENANT_ID` de otro directorio da el error `AADSTS700016`. + +## 2. Dar permisos + +Con el flujo *client credentials* se usan permisos de **aplicación**, no delegados. + +1. **API permissions → Add a permission → Microsoft Graph → Application permissions**. +2. Agrega solo lo que el código usa: + +| Permiso | Para qué | Dónde se usa | +|---------|----------|--------------| +| `Mail.Read` | Listar la bandeja de entrada y descargar adjuntos | `get_emails`, `download_attachments` | +| `Mail.Send` | Enviar las notificaciones | `send_email` | + +3. Pulsa **Grant admin consent for **. Sin el consentimiento de administrador los permisos de aplicación no tienen efecto, aunque aparezcan en la lista. + +> **Ojo:** un permiso de aplicación de correo vale, por defecto, para **todos los buzones** del tenant. Conviene limitarlo al buzón del proyecto con una política de acceso de aplicaciones en Exchange Online (*Application Access Policy* o *RBAC for Applications*). Eso lo configura un administrador de Exchange. + +## 3. Crear el client secret + +1. **Certificates & secrets → Client secrets → New client secret**. +2. Descripción y vencimiento (el portal permite hasta 24 meses). +3. Al crearlo, copia la columna **Value** y guárdala de inmediato en `CLIENT_SECRET`. **Solo se muestra una vez.** + +Se confunde con frecuencia: la columna **Secret ID** es un identificador, no sirve como secret. Si usas el *Secret ID* el error es `AADSTS7000215`. + +Cada secret **vence**. Anota la fecha en un calendario: cuando vence, el demonio deja de poder autenticarse y no lee ni envía correo (error `AADSTS7000222`). Para renovar sin cortes, crea el secret nuevo antes, actualiza el `.env`, reinicia el demonio y recién entonces borra el viejo. + +## 4. Completar el `.env` + +``` +CLIENT_ID = +TENANT_ID = +CLIENT_SECRET = +EMAIL = buzon@tu-dominio.com +``` + +El `.env` no se sube a git. No pegues el secret en chats, tickets ni commits. + +## 5. Verificar + +Pide un token sin enviar nada. Imprime solo el resultado, no el secret: + +```bash +python -c " +import re, outlook_utilities as o +try: + o.get_access_token(); print('OK: token obtenido') +except Exception as e: + print('ERROR', re.findall(r'AADSTS\d+', str(e)) or e)" +``` + +Un `OK` confirma `CLIENT_ID`, `TENANT_ID` y `CLIENT_SECRET`. No confirma los permisos sobre el buzón: eso se comprueba al listar o enviar un correo, por ejemplo con `tools/previsualizar_plantillas.py --escenario aceptado_sin_pago --enviar tu@correo`. + +## Errores frecuentes + +| Código | Significa | Qué revisar | +|--------|-----------|-------------| +| `AADSTS7000222` | El client secret **venció** | Crear un secret nuevo (paso 3) | +| `AADSTS7000215` | Secret inválido | Se usó el *Secret ID* en vez del *Value*, o hay un error al copiarlo | +| `AADSTS700016` | La aplicación no existe en ese directorio | `CLIENT_ID` y `TENANT_ID` deben ser de la misma aplicación (paso 1) | +| `AADSTS90002` | El tenant no existe | `TENANT_ID` mal escrito | +| `403` / `ErrorAccessDenied` al leer o enviar | Faltan permisos o consentimiento, o una política de acceso excluye al buzón | Paso 2 y la política de Exchange | +| `404` / `MailboxNotFound` | El buzón de `EMAIL` no existe o no tiene licencia | Revisar `EMAIL` | + +Para cualquier código `AADSTS`, el mensaje completo trae un *Trace ID* y una explicación; la lista oficial está en la documentación de Microsoft Entra, sección de códigos de error de autenticación.