Autenticación
La API de Kadu usa un access token de la Cuenta Kobana para autenticar
todas las solicitudes, en el header Authorization: Bearer, como las demás
APIs de Kobana.
curl -H "Authorization: Bearer $KOBANA_TOKEN" \
-H "Content-Type: application/json" \
https://api.kadu.ia.br/v1/me
El token
El token es un access token emitido por el Authorization Server de Kobana
(account.kobana.com.br). Kadu solo lo verifica: no guarda una clave de
firma y no puede emitir ningún token.
- Algoritmo:
RS256, y soloRS256. - Tipo: el encabezado del token debe tener
typ: at+jwt(RFC 9068). Otro JWT del mismo emisor, como un ID token, se rechaza. - Clave: pública, y descubierta, no configurada. El identificador del
emisor es una URL, y el endpoint de las claves (
jwks_uri) se lee del documento de metadata RFC 8414 publicado bajo ella (/.well-known/oauth-authorization-server). Cuando el Authorization Server rota la clave, Kadu la sigue solo. - Cuándo se llama al Authorization Server: nunca para verificar un token,
porque la verificación de la firma es local. Lo que viene de él es el
conjunto de claves, que se guarda en caché. Una consulta solo ocurre con la
caché vacía, con el conjunto en caché hace más de una hora, o cuando llega un
token con un
kidque no está en la caché (una rotación; como máximo una nueva consulta cada 30 segundos). Cada consulta tiene un timeout de 5 segundos.
Claims
| Claim | Descripción |
|---|---|
iss | El identificador del Authorization Server, como URL: https://account[.{env}].kobana.com.br. |
aud | Esta API, como URL: https://api.kadu.ia.br (staging: https://api.staging.kadu.ia.br). Puede ser una lista: la regla es contiene, no igualdad, así que un token puede dirigirse a más de una API de Kobana. |
exp | Obligatoria. Un token sin expiración se rechaza. |
org | La organización en nombre de la cual actúa el token, y es obligatoria. Es ella la que delimita toda respuesta. Un token sin org se rechaza, en lugar de caer en el sub. |
sub | La persona, nunca la organización. Va a la auditoría. |
email | Cuando está presente, vincula el token a una persona de la organización, y también vale su rol. Un token de integración, sin persona, vale solo por los alcances. |
jti | Id único del token, usado en la revocación y en el límite de solicitudes. |
scope | Alcances separados por espacio (abajo). |
:::info Verifica el entorno
El aud de producción no vale en staging, y viceversa. No reutilices el token
entre entornos.
:::
Probar el token
GET /v1/me dice quién está detrás del token. Es la única ruta sin verificación
de alcance, justamente para que pruebes un token nuevo.
Alcances
Los alcances tienen dos ejes ortogonales: el recurso, siempre con el
prefijo de la app (kadu/tasks), y el nivel de acceso, un alcance global
sin prefijo: read, write, delete, import, export o all. Un recurso
sin verbo significa lectura. Todo lo demás exige los dos: el alcance del
recurso y el nivel.
El recurso de una ruta es el primer segmento después de /v1:
/v1/executions/{id}/logs es del recurso executions.
| Alcance | Concede lectura de |
|---|---|
kadu/organizations | la organización del token |
kadu/workspaces | workspaces |
kadu/activities | actividades |
kadu/tasks | tareas, la verificación previa del lanzamiento y el endpoint de lanzamiento (el lanzamiento en sí es write) |
kadu/executions | ejecuciones, logs, eventos, pendientes y la búsqueda (cancelar y continuar son write) |
kadu/todos | pendientes (resolver es write) |
kadu/files | archivos de entrada y de salida |
kadu/environments | entornos |
kadu/secrets | secrets: clave, notas y metadatos. El valor nunca lo devuelve ningún endpoint |
kadu/schedules | programaciones |
kadu/memories | memorias |
kadu/webhooks | webhooks (rotar el signing secret es write) |
kadu/webhook_deliveries | entregas de webhook (reenviar es write) |
kadu/repository | el Playbook (sincronizar es write) |
kadu/usage | uso y costo |
kadu/users | miembros de la organización |
kadu/memberships | vínculos de personas con la organización |
kadu/roles | roles |
kadu/system_events | eventos de sistema |
kadu/all | comodín del eje de recurso: lee todos los recursos anteriores y no concede ningún nivel |
| Nivel de acceso | Concede |
|---|---|
read | Lectura. El alcance del recurso ya la implica; en un token sin alcance kadu/…, lee todos los recursos |
write | Todo POST, PUT y PATCH en los recursos que el token lleva: crear, modificar, lanzar, cancelar, sincronizar, rotar secreto, reenviar entrega. No elimina |
delete | Todo DELETE en los recursos que el token lleva, y nada más |
import | Importación masiva. Ningún endpoint de esta API importa en masa hoy |
export | Exportación masiva. Ningún endpoint de esta API exporta en masa hoy |
all | Todos los niveles anteriores |
Qué nivel exige cada endpoint
Un nivel por solicitud, dado por el método HTTP. Ningún nivel sustituye a otro:
write no elimina, y delete no escribe.
| Solicitud | Exige |
|---|---|
GET | El alcance del recurso (kadu/tasks) |
POST, PUT, PATCH | El alcance del recurso + write (kadu/tasks write) |
DELETE | El alcance del recurso + delete (kadu/tasks delete); write no basta |
GET /v1/me | Cualquier token válido, sin verificación de alcance |
Toda eliminación es un DELETE (el recurso recibe deleted_at) y todo
DELETE es una eliminación.
Tres ejemplos: kadu/executions lee ejecuciones y no cancela; kadu/tasks write también crea, modifica y lanza tareas, pero no las elimina;
kadu/tasks write delete hace las tres cosas. Ninguno de ellos alcanza los
secrets.
La forma granular kadu/tasks:write (o kadu/tasks:delete) es una excepción
de la gramática, no el formato estándar: satisface por sí sola los dos ejes de
ese recurso y existe para "lee un recurso, escribe otro". kadu/* es un
comodín de registro y nunca se emite en un token: la comparación aquí es
siempre literal.
Un token que lleva alcances kadu/… queda limitado a los recursos que ellos
nombran, y los niveles actúan solo dentro de ellos. Un token sin alcances
kadu/… queda limitado por el nivel: lee con read, write o all; escribe
con write o all; elimina con delete o all. Un token sin ninguno de los
dos no alcanza nada más allá de GET /v1/me.
Un alcance insuficiente responde 403 INSUFFICIENT_SCOPE, con los niveles que
bastarían en details.required y los alcances del token en details.granted.
Pipeline de validación
En este orden:
- Extrae
Authorization: Bearer <jwt>. - Verifica la firma con la clave pública del Authorization Server, aceptando
solo
RS256ytyp: at+jwt. - Valida
iss, que elaudcontiene esta API, y queexpestá presente y en el futuro. - Comprueba si el
jtifue revocado. - Resuelve la organización por el
org. - Aplica el límite de solicitudes del token.
- Verifica el alcance contra el endpoint.
- Con una persona en el token, verifica su rol en la organización (Permisos).
Aislamiento entre organizaciones
Toda consulta se filtra por la organización del org. No hay forma de apuntar a
otra organización por el cuerpo o por el query. Un recurso de otra organización
responde 404 NOT_FOUND, y no 403, para no revelar que existe.
Modos de falla
| HTTP | code | Causa |
|---|---|---|
| 401 | INVALID_TOKEN | JWT ausente, mal formado, con firma inválida o con otro typ |
| 401 | INVALID_AUDIENCE | aud de otra app o de otro entorno |
| 401 | INVALID_ISSUER | emisor distinto del Authorization Server de Kobana |
| 401 | TOKEN_EXPIRED | exp en el pasado |
| 401 | TOKEN_REVOKED | jti revocado |
| 403 | UNKNOWN_ORGANIZATION | el org apunta a una organización que Kadu no conoce |
| 403 | INSUFFICIENT_SCOPE | token sin el alcance exigido |
| 403 | USER_PERMISSION_DENIED, NOT_A_MEMBER | el rol de la persona del token no lo permite, o ella no pertenece a la organización (Permisos) |
| 429 | RATE_LIMITED | límite del token excedido (Límites) |
| 503 | AS_UNAVAILABLE | no se pudieron obtener las claves de firma del Authorization Server. La verificación en sí es local, así que esto solo ocurre en los momentos listados en Cuándo se llama al Authorization Server. No es un problema de tu token: intenta de nuevo después del Retry-After. Es 5xx a propósito: un 401 te mandaría a depurar una credencial buena durante una indisponibilidad nuestra. |
Mira Errores para el envelope completo.
Buenas prácticas
- Nunca versiones un token en git. Usa variables de entorno o una bóveda (AWS Secrets Manager, Vault…).
- Usa un token por integración: se puede revocar uno sin tumbar los demás.
- Pide los alcances mínimos:
kadu/executionspara quien solo sigue,kadu/tasks writepara quien lanza,deletesolo para quien elimina. - Revoca de inmediato cualquier token filtrado.