Cambios de OAuth
Historial de cambios del servidor OAuth 2.1 de UTILIA OS y de lo que lo rodea: cambios incompatibles, retiradas con fecha, novedades y refuerzos de seguridad.
Actualizado el . 8 min de lectura
Esta página reúne los cambios del servidor OAuth 2.1 de UTILIA OS que afectan a quien ya tiene una integración: qué cambió, desde cuándo y qué tienes que adaptar. Las entradas van de la más reciente a la más antigua. Las versiones exactas de los SDK están en el CHANGELOG.md de cada paquete y en Versiones y compatibilidad del SDK.
Retiradas pendientes
Próximas retiradas
16 oct 2026
Dos endpoints antiguos
GET /api/oauth/user-scopes pasa a GET /api/oauth/user/scopes, y POST /api/oauth/apps/revoke, a POST /api/oauth/apps/:clientId/revoke.1 feb 2027
Campo scope de /api/oauth/apps
Se sustituye por el campo permissions.2 mar 2027
Fin de las transiciones de scopes
Los tokens anteriores al 2 de septiembre de 2026 dejan de leer datos sensibles y personas de contacto con los scopes antiguos.
Los dos endpoints antiguos ya responden con las cabeceras Deprecation: true, Sunset: Thu, 16 Oct 2026 00:00:00 GMT y Link al sustituto. Si las ves en tus registros, tienes código que todavía llama a un endpoint antiguo.
Estado actual
| Elemento | Valor |
|---|---|
| Access token | 1 hora (3.600 s) |
| Refresh token | 90 días desde la autorización; rota en cada renovación |
| Código de autorización | 60 segundos, un solo uso |
| PKCE | Obligatorio, solo S256 |
| SDK oficiales | @utilia-os/sdk-js y utilia-sdk, versión 4.1.0 |
9 de octubre de 2026
- Un cliente desactivado invalida sus tokens. Al desactivar OAuth en una aplicación, sus access tokens dejan de valer en el acto, aunque no consten revocados: la introspección responde
active: falsey la renovación falla coninvalid_client. invalid_clientya no dice qué falló. EnPOST /api/oauth/tokenyPOST /api/oauth/introspect, un cliente inexistente, desactivado o vencido, un secreto que falta o que no es correcto y un cliente público en la introspección responden lo mismo:401conClient authentication failed. Antes cada caso tenía su texto (Client not found,Client is inactive,Client secret required...) y con ellos se podía averiguar qué clientes existen. Si tu integración leía esos textos, compara solo el campoerror. Las causas posibles están en Problemas frecuentes con OAuth.- El cierre de sesión exige un
id_token_hintfirmado por UTILIA OS. Se comprueba su firma RS256 con la clave pública de/api/oauth/jwksy el claimisses obligatorio. - La marca de aplicación propia y la de «Verificada por UTILIA» solo las asigna UTILIA OS. Si otra organización pide
is_first_partyoverifiedcon valortrue, recibe403conSAAS_ADMIN_REQUIRED_FOR_OAUTH_TRUST.
5 de octubre de 2026
La persona puede conceder menos scopes de los que pides
La pantalla de consentimiento permite desactivar grupos de permisos antes de autorizar. Los de identidad (openid, profile, email) no se pueden desactivar. El token lleva solo lo que quedó activado, y las renovaciones conservan ese conjunto reducido.
Si tu aplicación no manda scope, la pantalla enseña ahora el conjunto por defecto que se concede (los scopes permitidos del registro del cliente o, si no tiene, los de identidad), y la persona también puede estrecharlo. Antes ese conjunto se concedía sin enseñarse.
Qué hacer: lee el campo scope de la respuesta de POST /api/oauth/token y desactiva lo que dependa de un scope no concedido. Si con la selección un servidor MCP se quedara sin ningún scope útil, la pantalla no deja autorizar, así que nunca se emite un token que el servidor rechazaría. Detalle en Pantalla de consentimiento.
Compartir documentación con enlace tiene scope propio
Crear un enlace público a un documento exige ahora dev:docs:share, que no viaja en ningún conjunto. Antes bastaba con dev:docs:update. Los tokens anteriores no lo llevan y tienen que volver a autorizarse.
14 de septiembre de 2026
El límite de los documentos de descubrimiento (/.well-known/*) sube de 120 a 600 peticiones por minuto y dirección IP: un cliente MCP con varios servidores configurados los pide muchas veces al arrancar.
3 de septiembre de 2026
- Fusiones con scope propio:
crm:clients:merge,crm:contacts:mergeycrm:leads:mergeno viajan en ningún conjunto, tampoco encrm:full. Se piden por su nombre. - Acceso al portal del cliente con scope propio: la herramienta
portal_accessexigecrm:portal:viewocrm:portal:managey ya no se abre concrm:contacts:update, sin periodo de transición.
2 de septiembre de 2026
- Datos sensibles con scope propio: el NIF, el límite de crédito y el descuento del cliente pasan a
crm:clients:view-sensitive, y los datos bancarios y fiscales del proveedor, afinance:suppliers:view-sensitive. Los tokens anteriores siguen leyéndolos con el scope antiguo hasta el 2 de marzo de 2027. - Personas de contacto de los proveedores: pasan a
finance:supplier-contacts:viewyfinance:supplier-contacts:manage, fuera definance:readyfinance:write. Los tokens anteriores siguen operando confinance:suppliers:viewyfinance:suppliers:updatehasta el 2 de marzo de 2027.
28 de agosto de 2026
Ningún conjunto concede ya la administración de la organización: org:team:*, org:observability:* y org:settings:update se piden por su nombre. Hasta esta fecha los expandía crm:full. Solo org:settings:view sigue viajando en crm:read y crm:full.
28 de julio de 2026
Cambios en el alcance de los tokens y en la respuesta de GET /api/oauth/apps.
El campo scope de GET /api/oauth/apps se retira el 1 de febrero de 2027
Sigue llegando hasta esa fecha, pero ha cambiado de significado: ya no lista todo lo que hay en el token, sino solo lo que el plan de la organización deja ejercer. Lo demás no se ha revocado: sigue concedido, pero pertenece a aplicativos no contratados y el servidor MCP lo deniega.
Campos nuevos para sustituirlo:
- permissionsarray
- Permisos ejercibles con el plan actual. Cada elemento: scope, description (en castellano) e impact (destructive, write, read o identity).
- permissionCountnumber
- Número de permisos ejercibles. Siempre igual a la longitud de permissions.
- unavailablePermissionCountnumber
- Permisos concedidos que el plan actual no deja ejercer.
- unavailableModulesarray
- Aplicativos no contratados de los que vienen esos permisos. Cada elemento: key y label.
La forma completa de la respuesta está en OAuth: visión general.
Una renovación solo puede estrechar el alcance
Antes, grant_type=refresh_token recalculaba el alcance a partir de los permisos vigentes de la persona, así que un token podía crecer más allá de lo que se consintió. Ahora el token renovado es siempre un subconjunto del consentido, acotado además por el servidor al que está atado. Para ampliar el alcance hay que volver a autorizar.
Si la persona pierde todos los permisos del servidor del token, la renovación revoca la cadena y responde invalid_grant. Los tokens solo de identidad (openid, profile, email) no se ven afectados.
Los tokens emitidos antes del cambio se revocaron al aplicarlo, salvo los solo de identidad: su primera renovación respondió invalid_grant y hubo que autorizar una vez más.
Qué hacer:
- Sustituye
scopeporpermissionsantes del 1 de febrero de 2027, y muestra tambiénunavailablePermissionCountyunavailableModules, que explican por qué faltan permisos. - Trata
invalid_grantvolviendo a pedir la autorización. - No cuentes con que un token gane scopes solo: pídelos en una autorización nueva.
12 de mayo de 2026
support:writeincluyesupport:tickets:create: los clientes consupport:writepueden abrir tickets sin volver a autorizar, porque el conjunto se resuelve en el servidor. Si no quieres esa ampliación, revoca el token y pide solo los scopes individuales que necesites.- Abrir tickets por MCP: la herramienta
ticketsadmitecreate. Quien abre el ticket es siempre la persona dueña del token, el título y la descripción se limpian de HTML, y hay un máximo de 10 tickets por hora y persona por esta vía.
16 de abril de 2026
Cambios incompatibles
- El access token dura 1 hora en lugar de 30 días. Toda integración tiene que renovar con el refresh token; el valor exacto llega en
expires_in. - El refresh token rota en cada renovación. Reutilizar uno ya rotado revoca la cadena y responde
invalid_grant(Refresh token has been rotated). Si dos renovaciones compiten a la vez por el mismo, la que pierde recibeRefresh token rotated concurrently. Detalle en Rotación del refresh token.
Endpoints que se retiran el 16 de octubre de 2026
GET /api/oauth/user-scopespasa aGET /api/oauth/user/scopes, que además admiteclient_idpara devolver la información pública del cliente.POST /api/oauth/apps/revokepasa aPOST /api/oauth/apps/:clientId/revoke, con el identificador en la ruta y sin cuerpo.
Novedades
GET /api/oauth/clients/:clientId: información pública de un cliente. Responde{ "known": false }con200si no existe, para impedir enumerar clientes.GETyPOST /api/oauth/logout: cierre de sesión iniciado por tu aplicación (OpenID Connect RP-Initiated Logout 1.0), con el campopost_logout_redirect_urisen el registro de clientes (hasta 10 direcciones).- Parámetros
prompt(none,login,select_account,consent) ylogin_hinten/api/oauth/authorize.
Seguridad
- Las direcciones de los clientes (
redirect_uris,client_uri,logo_uri,post_logout_redirect_uris) solo admitenhttpyhttpsy rechazan los hosts internos.localhost,127.0.0.0/8y::1se admiten en las direcciones de vuelta, porque los clientes nativos las necesitan. login_hintsolo admite letras, dígitos y. _ @ + -, con un máximo de 255 caracteres.- Los tokens de una persona cuya cuenta deja de estar activa se rechazan de inmediato.
POST /api/oauth/introspectexige autenticación de cliente.
Límites de uso establecidos
| Endpoint | Límite |
|---|---|
GET /.well-known/* | 120 por minuto (600 desde el 14 de septiembre de 2026) |
POST /api/oauth/register | 30 por hora |
POST /api/oauth/token y POST /api/oauth/revoke | 60 por minuto |
POST /api/oauth/introspect | 120 por minuto |
GET /api/oauth/scopes | 60 por minuto |
GET /api/oauth/clients/:clientId y /api/oauth/logout | 30 por minuto |
8 de abril de 2026
Los SDK admiten el parámetro theme (light o dark) al construir la URL de autorización.
2 de abril de 2026
- OAuth en las aplicaciones externas: se activa desde la ficha de cada aplicación, en Gestión de proyectos › Integraciones.
- OpenID Connect:
/.well-known/openid-configuration,/api/oauth/userinfo,/api/oauth/jwkseid_tokenfirmados con los claims estándar. - SDK:
getAuthorizationUrl()yget_authorization_url()gestionan PKCE solos;handleCallback(code)yhandle_callback(code)recuperan elcode_verifiery comprueban elstate;isAuthenticated(),logout()y, en JavaScript,loginWithPopup().