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.writepara 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#
statees obligatorio y se devuelve tal cual.- PKCE es obligatorio, con S256.
- Las comparaciones de hash son de tiempo constante.
/oauth/tokentiene 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.