OAuth y tokens¶
OAuth 2.1¶
- Flujo de código de autorización solo con PKCE S256.
- Registro dinámico de clientes (RFC 7591) para clientes públicos, si
enabledcrestá activo (por defecto). - Documentos de metadatos de client id por HTTPS, si
allowcimdestá activo (por defecto). Se rechazan los hosts que resuelven a direcciones privadas o link-local. - El registro y la descarga de metadatos tienen límite de peticiones.
- El usuario entra en Moodle y aprueba los alcances en una página de consentimiento. Después, las tools se ejecutan como ese usuario.
Endpoints¶
El emisor (issuer) es {wwwroot}/local/mcp.
| Función | URL |
|---|---|
| Metadatos del recurso protegido | {wwwroot}/local/mcp/wellknown.php?doc=resource |
| Autorización | {wwwroot}/local/mcp/authorize.php |
| Token | {wwwroot}/local/mcp/token.php |
| Registro | {wwwroot}/local/mcp/register.php |
| Revocación | {wwwroot}/local/mcp/revoke.php |
Discovery¶
La cabecera WWW-Authenticate de un 401 siempre incluye una URL resource_metadata bajo /local/mcp/.
A los clientes que la respetan no les hace falta nada más.
Los clientes que siguen RFC 8414 piden además:
{wwwroot}/.well-known/oauth-authorization-server/local/mcp{wwwroot}/.well-known/openid-configuration/local/mcp{wwwroot}/local/mcp/.well-known/openid-configuration{wwwroot}/.well-known/oauth-protected-resource/local/mcp/server.php(metadatos del recurso protegido)
Para esos, añade reescrituras. Apache, con la raíz de documentos en la raíz web de Moodle (public/ en 5.x):
RewriteEngine On
RewriteRule ^\.well-known/oauth-protected-resource /local/mcp/wellknown.php?doc=resource [L,QSA]
RewriteRule ^\.well-known/oauth-authorization-server /local/mcp/wellknown.php?doc=as [L,QSA]
RewriteRule ^\.well-known/openid-configuration /local/mcp/wellknown.php?doc=as [L,QSA]
RewriteRule ^local/mcp/\.well-known/openid-configuration /local/mcp/wellknown.php?doc=as [L,QSA]
nginx:
location ~ ^/\.well-known/oauth-protected-resource {
rewrite ^ /local/mcp/wellknown.php?doc=resource last;
}
location ~ ^/\.well-known/(oauth-authorization-server|openid-configuration) {
rewrite ^ /local/mcp/wellknown.php?doc=as last;
}
location = /local/mcp/.well-known/openid-configuration {
rewrite ^ /local/mcp/wellknown.php?doc=as last;
}
El servidor integrado de PHP no lee .htaccess. Pásale el router del plugin:
php -S 127.0.0.1:8081 -t /ruta/a/moodle /ruta/a/moodle/local/mcp/router.php
# Moodle 5.x:
php -S 127.0.0.1:8082 -t /ruta/a/moodle/public /ruta/a/moodle/public/local/mcp/router.php
Alcances¶
| Alcance | Incluye | Capability necesaria |
|---|---|---|
read |
Tools de lectura | local/mcp:read |
write |
read + tools de escritura |
local/mcp:write |
admin |
write + read |
local/mcp:admin |
Un token sin el alcance que pide una tool recibe HTTP 403 con WWW-Authenticate: Bearer error="insufficient_scope".
Duración y revocación de tokens¶
- Token de acceso: 3600 s por defecto (60–86400). Código de autorización: 300 s (30–600). Token de refresco: 30 días (de 1 hora a 365 días). Consulta Ajustes.
- Los tokens de refresco rotan en cada uso. Si se presenta uno ya usado, se revoca toda su familia de tokens.
- Revocar un token de acceso en
revoke.phprevoca también su token de refresco y el resto de la familia. - Los administradores pueden listar y revocar tokens con la CLI.
- Tokens, códigos de autorización y secretos de cliente se guardan solo como hash SHA-256.
- Una tarea diaria de limpieza (03:15) borra códigos y sesiones caducados y filas antiguas del límite de peticiones. Los tokens revocados se guardan dos semanas para seguir detectando la reutilización de tokens de refresco; los de acceso caducados se borran a la semana.
Token de servicio web como alternativa¶
Con Aceptar tokens de servicio web de Moodle (allowwstoken) activado, Authorization: Bearer puede llevar
un wstoken de Moodle en lugar de un token OAuth. Se comprueba en external_tokens (caducidad, restricción de IP,
estado del usuario). La llamada tiene entonces todos los alcances MCP que permitan los permisos del usuario.
Déjalo desactivado salvo que ya gestiones tokens de servicio web y aceptes que no se acotan tanto como los de OAuth.