Ir al contenido
Bondry

OAuth 2.1 para apps

Código de autorización con PKCE, refresh tokens rotativos, scopes y los endpoints que llama una app.

Las API keys cubren integraciones servidor a servidor. OAuth es para una app que actúa en nombre de un miembro, con el consentimiento de ese miembro: una app móvil, o una herramienta de terceros que un miembro conecta a su cuenta.

Flujos#

  • Código de autorización con PKCE (S256), obligatorio para todo cliente. Los clientes públicos, como las apps móviles, no llevan secreto; los clientes confidenciales pueden tener uno.
  • Los refresh tokens rotan. Cada uso emite uno nuevo e invalida el anterior. Reutilizar un refresh token rotado revoca toda la familia, así es como se detecta un token robado.
  • Sin flujo implícito, sin password grant. La autorización por dispositivo no está en la v1.

Endpoints#

Endpoint Qué hace
GET /oauth/authorize La pantalla de consentimiento, dentro de la sesión del miembro, con los scopes explicados en lenguaje simple
POST /oauth/token Grants authorization_code y refresh_token
POST /oauth/revoke Revoca un token
GET /oauth/userinfo Perfil mínimo, según los scopes otorgados
GET /.well-known/oauth-authorization-server Metadatos, RFC 8414

Vida útil de los tokens#

Artefacto Vida útil Notas
Código de autorización 60 segundos Un solo uso
Access token 1 hora Opaco, no un JWT; se guarda como hash SHA-256
Refresh token 30 días Rotativo

Los access tokens son opacos a propósito. Un JWT que no se puede revocar antes de expirar es la elección equivocada para una app que un miembro puede desconectar en cualquier momento.

URIs de redirección#

Se registran por cliente y se comparan de forma exacta. Los esquemas personalizados (bondry-app://callback) y el loopback (http://127.0.0.1:<port>) se permiten para apps nativas; localhost solo se acepta en un entorno local.

Scopes#

Los mismos scopes que las API keys, declarados por el core y por cada módulo: members.read, community.write, blog.read, messages.*, notifications.*, account.*, más profile para identidad mínima y offline_access para un refresh token.

El gate acepta un bearer token de OAuth o de una API key. Un token de OAuth lleva al miembro, así que los permisos del grupo del miembro se aplican por encima del scope.

Advertencia Un scope nunca amplía lo que el miembro no puede hacer. Solicitar community.write para un miembro que no puede publicar sigue fallando.

Registrar un cliente#

System > API > OAuth clients en el panel: nombre, logo, sitio web, redirect URIs y si el cliente es confidencial. El secreto de un cliente confidencial se muestra una sola vez. Cada cambio queda registrado en el admin log.

Lo que ve el miembro#

  • La pantalla de consentimiento, renderizada con el tema del sitio, con el nombre y logo de la app, los scopes explicados, una advertencia explícita cuando la app no es de primera parte, y los botones Permitir y Denegar.
  • Account > Connected apps, con la lista de cada app autorizada, sus scopes, el último uso y un botón que revoca la app y toda su familia de tokens.

La revocación es en cascada: banear o eliminar a un miembro, o revocar el cliente, revoca los tokens.

Notas de implementación#

  • state es obligatorio y se devuelve tal cual.
  • PKCE es obligatorio, con S256.
  • Las comparaciones de hash son de tiempo constante.
  • /oauth/token tiene rate limit por cliente y por IP.
  • Los tokens nunca aparecen en un log.

Cada flujo y cada rechazo tiene un test: verifier de PKCE incorrecto, redirect URI diferente, código reutilizado, refresh token rotado reutilizado, scope no otorgado, miembro baneado.