Ir al contenido

Autenticación y claves de API

Los programas se autentican en la API de PlusPanel con una clave de API enviada como bearer token. El panel usa una sesión de navegador; la CLI puede obtener una clave por ti mediante un inicio de sesión en el navegador (device flow).

GET /api/v1/auth/me HTTP/1.1
Host: panel.example.com
Authorization: Bearer ppk_k3nmw2x7q4tz_8lV0m1Q2…
  • Una clave tiene la forma ppk_<id de clave>_<secreto>. El id de la clave (12 caracteres) es público: aparece en las listas de claves y en el registro de auditoría. El secreto se muestra una sola vez, al crear o rotar la clave. PlusPanel guarda solo un hash de la clave y no puede volver a mostrarla.
  • Una petición con la cabecera Authorization ignora por completo las cookies: sin sesión y sin token CSRF.
  • Una clave mal formada, desconocida, caducada o revocada recibe 401 con el código invalid_api_key y WWW-Authenticate: Bearer error="invalid_token".
  • GET /api/v1/auth/me te dice en nombre de quién actúa la clave, con qué roles y permisos.

Los scopes salen de los mismos roles y permisos que el panel; no hay un segundo sistema de permisos. Cada permiso pertenece a un recurso y es de lectura o de escritura:

Scope Permite
<recurso>:read Leer ese recurso, por ejemplo servers:read, accounts:read
<recurso>:write Modificarlo (y leerlo: write incluye read), por ejemplo sites:write
*:read Leer todos los recursos
* Todo lo que puede hacer el usuario (no existe *:write: se escribe *)

Los recursos son accounts, alerts, apikeys, audit, backups, databases, dns, jobs, mail, observability, plans, runtime, security, servers, sftp, sites, storage, tenant, updates, users, waitlist y webhooks; GET /api/v1/api-keys/scopes los lista con los permisos que cubre cada scope, y el panel muestra la misma lista al crear una clave. En las peticiones GET, el scope read de un recurso cubre también las lecturas que el panel protege con un permiso de gestión (por ejemplo, la lista de sitios), salvo unas pocas lecturas estrictas que devuelven un secreto o los propios datos: la salida única de un job, el contenido de archivos y el terminal web (accounts), los enlaces de invitación (users), las restauraciones y descargas de copias de seguridad (backups) y las pruebas de laboratorio (jobs) necesitan el scope write de su recurso.

Una clave nunca hace más que su usuario. Una petición hecha con una clave solo se permite si se cumplen las dos condiciones:

  1. el rol del usuario (y, para revendedores y clientes, las cuentas a las que acceden) la permite, exactamente como en el panel, y
  2. uno de los scopes de la clave cubre el permiso.

Si el usuario pierde un rol, sus claves también lo pierden. Algunas acciones de autoservicio nunca están disponibles con una clave, sean cuales sean sus scopes: cambiar la contraseña o un segundo factor, gestionar sesiones, la reautenticación (step-up), la suplantación de usuarios y aprobar un inicio de sesión de la CLI. GET /auth/me, GET /tenant/edition y GET /api-keys/scopes funcionan con cualquier clave.

A una clave a la que le falta un scope se le responde 403 insufficient_scope (el mensaje nombra el scope necesario); un endpoint que requiere una sesión iniciada responde 403 api_key_not_allowed.

  • Una clave personal actúa en tu nombre. Deja de funcionar cuando tu usuario se desactiva o se elimina.
  • Una clave de organización actúa como un usuario de servicio dedicado de la organización (rol admin, sin contraseña, sin posibilidad de iniciar sesión). Sobrevive a las personas que la crearon y la gestionan los administradores de la organización (crearla requiere el permiso apikeys.manage a nivel de organización). Úsala para integraciones que deben seguir funcionando cuando cambia el equipo. Una clave de organización solo puede crear claves de organización.

Las claves creadas por el inicio de sesión de la CLI en el navegador son claves personales (origen device, válidas 90 días por defecto; ver más abajo).

  • La caducidad es opcional y se fija al crear la clave (no se puede cambiar después). Una clave caducada recibe 401 invalid_api_key.
  • La rotación (POST /api-keys/{id}/rotate) da a la clave un secreto nuevo y conserva su id, sus scopes y su configuración. Con grace_seconds (como máximo 86400) el secreto anterior sigue siendo válido durante un periodo de gracia mientras despliegas el nuevo. Una clave personal solo la rota su propietario.
  • La revocación es inmediata y definitiva.
  • El panel muestra el último uso de cada clave (hora y dirección IP) y su número diario de peticiones.

Una clave se puede limitar a una lista de redes (CIDR o direcciones sueltas, IPv4 e IPv6; un CIDR con bits de host, como 192.0.2.7/24, se rechaza). Una petición desde cualquier otra dirección recibe 403 api_key_ip_denied, aunque la clave sea válida.

Una clave solo puede crear o modificar claves con el scope apikeys:write, y solo con scopes, caducidad, lista de IP y límite de peticiones no más amplios que los suyos (si no, 403 api_key_wider_than_caller). Cada creación, rotación, revocación, cambio y rechazo queda en el registro de auditoría.

pluspanel login de la CLI obtiene su clave mediante un inicio de sesión en el navegador con la forma de RFC 8628; otras herramientas pueden usar los mismos dos endpoints públicos (sin credenciales, sin Idempotency-Key):

  1. POST /api/v1/auth/device/code con {"client_name": "…"} responde con un device_code secreto, un user_code (XXXX-XXXX), la página /device del panel como verification_uri (y verification_uri_complete con el código), expires_in (600 segundos) e interval (5 segundos). Como máximo 10 códigos por minuto y 5 solicitudes pendientes por dirección (429 rate_limited).
  2. Muestra el user_code y abre la página. La persona inicia sesión como siempre, comprueba la solicitud (nombre, dirección, hora) y la aprueba (confirmando de nuevo su identidad si no lo ha hecho en los últimos 5 minutos) o la rechaza.
  3. Consulta POST /api/v1/auth/device/token con {"device_code": "…"} cada interval segundos. Hasta la decisión responde 400 con el código authorization_pending; slow_down indica que consultas demasiado rápido (suma 5 segundos al intervalo); access_denied y expired_token (pasados 10 minutos, con un código desconocido o cuando la clave ya se entregó) terminan el flujo. Son documentos problem: el error de RFC 8628 se lee en code.
  4. La primera consulta tras la aprobación responde 200 con token (se muestra una sola vez), key, tenant y user: una clave personal llamada CLI: <client_name>, con acceso completo o solo de lectura, según se aprobó.
Ventana de terminal
curl -fsS -X POST "$PLUSPANEL_URL/api/v1/auth/device/code" \
-H "Content-Type: application/json" -d '{"client_name": "deploy tool on laptop"}'
# {"device_code":"…","user_code":"BCDF-GHJK","verification_uri":"https://panel.example.com/device",
# "verification_uri_complete":"https://panel.example.com/device?code=BCDF-GHJK","expires_in":600,"interval":5}
curl -sS -X POST "$PLUSPANEL_URL/api/v1/auth/device/token" \
-H "Content-Type: application/json" -d '{"device_code": "…"}'
# antes de la decisión: 400 {"code":"authorization_pending", …}
# tras la aprobación: 200 {"token":"ppk_…","key":{…},"tenant":{"slug":…,"name":…},"user":{…}}

Cada clave tiene un presupuesto de peticiones por minuto (600 por defecto, en todas las ediciones; a una clave se le puede dar un límite menor). Consulta Convenciones → Límites de peticiones.

  • Una clave por integración, con los scopes mínimos que necesita y una fecha de caducidad.
  • Guarda las claves en un gestor de secretos o en una variable de entorno, nunca en el código fuente.
  • Para integraciones duraderas, mejor una clave de organización; para servidores con direcciones fijas, una lista de IP permitidas.
  • Rota las claves periódicamente, y de inmediato si una pudo filtrarse; revoca las que ya no uses.