Moodle 5.3: la API nueva por fin tiene OAuth de verdad (lo antiguo sigue con tokens)
ContenidoContents
Moodle 5.3 salió el 5 de octubre de 2026 y es la nueva versión LTS. Entre todo el cambio visual hay una sección pequeña en las notas que a mí me interesa más que el resto: «OAuth 2 support for routed web services».
Resumen honesto: la API nueva de Moodle por fin tiene OAuth de verdad. Pero lo antiguo, los web services de siempre basados en funciones externas, sigue funcionando con los tokens de siempre.
Qué es exactamente lo que llega
Moodle lleva unas versiones construyendo una API REST “con rutas” (las clases en el namespace route\api), separada del sistema clásico de funciones externas. En 5.3 esa API gana su propio servidor OAuth 2 dentro de core. Los tickets lo dejan bastante claro:
- MDL-89251: el backend del servidor OAuth 2 (esquema de base de datos, entidades, repositorios y descubrimiento dinámico de scopes).
- MDL-89181: un gestor de clientes. Según el UPGRADING.md,
\core\oauth2\server\client_managergestiona el ciclo de vida de los clientes, sus secretos y sus URIs de redirección. - MDL-88468: interfaz para administrar el servidor y los clientes.
- MDL-88472: las pantallas del flujo de login. La pantalla de login muestra qué cliente pide acceso, hay una nueva de «Continuar como [usuario]» y otra para confirmar los scopes.
- MDL-88473: revocación de tokens con un único endpoint
/revokesegún el RFC 7009. Siempre devuelve 200, aunque el token no exista, para no filtrar información. Si revocas un refresh token, caen también los access tokens emitidos a partir de él.
Es decir: clientes registrados, flujo de autorización con consentimiento del usuario, refresh tokens y revocación. Lo que esperas de un OAuth normal.
Tokens personales, pero bien hechos
Además del flujo OAuth completo llegan los personal access tokens (MDL-87706). Cada usuario los gestiona en /user/personalaccesstokens.php, y crearlos requiere la nueva capacidad moodle/api:createtoken (otra vez, según el UPGRADING.md).
Al crear uno le pones nombre, descripción, caducidad y scopes. El valor solo se puede copiar una vez. Después no se puede editar, solo revocar. Para scripts propios contra mi aula, esto es justo lo que quería.
Scopes por ruta, y obligatorios
Aquí está la parte que afecta a quien escribe plugins. La documentación de scopes explica que cuando una petición llega con un token OAuth 2 o un token personal, el router comprueba además los scopes. Y lo hace además de las capacidades, no en su lugar. Un token con el scope correcto no salta los permisos del usuario.
Cada ruta declara lo que necesita con el atributo #[scopeset]. Varios scopes en el mismo #[scopeset] son un AND; repetir el atributo es un OR. Si una ruta no necesita scope (un endpoint de estado, por ejemplo), hay que decirlo explícitamente con #[unscoped_resource].
Y no es opcional. Como cuenta el devupdate de 5.3, hay un test PHPUnit de core que recorre todas las rutas de route\api y falla si alguna no lleva ninguno de los dos atributos. Si tienes un plugin con rutas, toca revisarlo.
Un detalle que me gusta: si un #[scopeset] referencia un scope que no existe en la versión de Moodle instalada, no se ignora. Se sustituye por un marcador que nunca se cumple. Falla cerrado, que es lo correcto.
Ojo también: la validación de scopes solo aplica a peticiones con token. Con sesión normal de Moodle no cambia nada.
Necesita Composer
El servidor usa el paquete league/oauth2-server, que no viene dentro de core. MDL-88576 añade una comprobación para que, si no has hecho composer install, Moodle muestre un aviso en lugar de romperse. En mi servidor toca añadir ese paso al proceso de actualización. Quien despliegue copiando el zip sin más tendrá que tenerlo en cuenta.
Lo que no cambia
Los web services clásicos (funciones externas, webservice/rest/server.php, el token de toda la vida) siguen como estaban. Este OAuth es para la API con rutas, no para lo antiguo.
Por eso mi conector local_sepe para teleformación del SEPE no gana nada. Es SOAP, habla con los servicios del SEPE y no toca la API REST nueva.
Dónde sí le veo sentido
En integraciones nuevas. Pienso sobre todo en servidores MCP: darle a un asistente acceso a Moodle con un token limitado a, por ejemplo, leer cursos, que el usuario aprueba en una pantalla y que puede revocar cuando quiera. Hasta ahora eso pasaba por un token de web service con demasiado poder y poca granularidad.
También para cualquier herramienta externa que hoy pide “un token de administrador” porque no hay otra forma. Con scopes por ruta se puede pedir solo lo necesario.
Mi plan
Actualizar el aula a 5.3 con calma, instalar las dependencias de Composer, crear un token personal con scopes mínimos y probar algo pequeño contra la API REST. Si funciona como promete la documentación, el siguiente paso será un MCP sencillo encima. Ya contaré.