Skip to main content
Los chats de grupo usan el mismo modelo de cifrado que X Chat 1:1: una clave de conversación compartida por los miembros, envuelta con la clave pública de identidad de cada miembro, con mensajes cifrados y firmados por el Chat XDK. Lo que cambia es la membresía, cómo creas la conversación y, a menudo, los campos cifrados de título/avatar de la conversación. Los flujos 1:1 están en Primeros pasos. Los detalles de los endpoints están en API reference → Conversations and messages.

Cómo difieren los grupos de 1:1

La criptografía sigue siendo: Chat XDK para claves y payloads; X API para crear el grupo, publicar los envoltorios de clave de los participantes, enviar mensajes y cargar eventos.

Crear el grupo y establecer claves

  1. Genera el ID de grupo con POST /2/chat/conversations/group/initialize — el data.conversation_id de la respuesta es el ID con prefijo g que usas en todo lo siguiente.
  2. Carga la clave pública de identidad y el public_key_version de cada miembro (rutas GET de public-key bajo Encryption keys; GET /2/users/public_keys obtiene varios usuarios en una sola solicitud). Verifica cada registro con verify_key_binding antes de usarlo (consulta la advertencia en Primeros pasos).
  3. Ejecuta prepare_group_create una vez, con todos los miembros (incluido tú), el ID con prefijo g, y las listas de IDs de miembros/administradores. Una llamada genera la clave de conversación, la envuelve para cada miembro y firma la creación con la identidad de sesión de set_identity — devuelve dos firmas de acción (el cambio de clave de conversación y la creación del grupo).
  4. POST /2/chat/conversations/group con los miembros/administradores del grupo, conversation_key_version, conversation_participant_keys (SDK encrypted_key → API encrypted_conversation_key) y ambas action_signatures. Los fallos de validación regresan como mensajes estables y legibles por humanos, por ejemplo "Too many members: adding these members would exceed the allowed group size." o "Cannot add all members: one or more of the requested members cannot be added to this conversation.".
  5. Guarda la clave de conversación en bruto y la versión para cifrar/descifrar.
prepare_group_create firma el title y avatar_url que pasas y los incrusta literalmente en el evento group-create. El servidor los verifica contra tu solicitud, así que los valores group_name / group_avatar_url en el cuerpo del POST deben ser idénticos byte a byte a lo que pasaste al SDK — de lo contrario, la llamada falla la validación de firma.
El mapeo del cuerpo para las claves de los participantes y las firmas de acción (message_id, encoded_message_event_detail, message_event_signature anidado) es el mismo que el POST de claves en Primeros pasos — claves de conversación. Cuando cambia la membresía, llama a prepare_group_members_change con los nuevos IDs de miembros más la lista actual (miembros, administradores, miembros pendientes y el título/avatar/TTL actuales si están definidos). Rota la clave de conversación y, como group create, devuelve dos firmas de acción — envía todo con POST a add members (POST /2/chat/conversations/{id}/members). Luego espera tráfico de key-change: trátalo como rotación de clave en Primeros pasos (extract_conversation_keys / decrypt_events, luego cifra con la última versión). Como prepare_group_members_change genera una clave de conversación nueva envuelta solo para la lista que pasas, los nuevos miembros reciben la nueva versión de clave y no pueden descifrar mensajes enviados con versiones anteriores. Lo contrario no es cierto: la rotación nunca revoca el acceso a versiones anteriores — cualquiera que ya tenga una clave vieja aún puede leer los mensajes cifrados con ella. Si sospechas que una clave de conversación fue expuesta, rota con prepare_conversation_key_change; esto protege solo los mensajes futuros.

Metadatos cifrados del grupo

Algunos campos de la conversación (por ejemplo el name o avatar URL de visualización) pueden llegar cifrados con la clave de conversación. Eso no es encrypt_message; es el par genérico encrypt / decrypt del Chat XDK (string UTF-8 dentro, texto cifrado en base64 fuera, con la clave de conversación en bruto). Si un campo dado se almacena cifrado lo decide el cliente que lo escribe: prepare_group_create firma y envía el título exactamente como lo proporcionas (la clave de conversación no existe hasta que esa llamada la genera, por lo que un título en el momento de creación no se puede cifrar con ella). Cuando lees una conversación cuyos campos son texto cifrado, descífralos con decrypt y la versión de clave que estaba activa cuando se escribió el campo.
Usa la versión actual de la clave de conversación que corresponde a esos metadatos. Si las claves rotaron, descifra con la versión que estaba activa cuando se escribió el campo (o sigue las reglas del producto si los metadatos siempre se reescriben en la rotación).

Mensajes y eventos

Enviar y recibir en un grupo es lo mismo que 1:1 una vez que tienes la clave de conversación en bruto: Siempre cifra con la última versión de clave tras una rotación por cambio de membresía.

Cambios de clave por parte de miembros que han abandonado el grupo

Los eventos de cambio de clave de un grupo son firmados por quien los realizó—a menudo el creador o un administrador. Si ese miembro más tarde abandona el grupo (o se desactiva), los endpoints de claves públicas dejan de devolver sus claves, por lo que la ruta de descifrado verificada (decrypt_events con claves de firma) falla en esos eventos de cambio de clave con signature missing or no matching signing key. Los eventos no están corruptos; simplemente ya no se sirve el material de verificación. Los grupos de larga duración deben esperar esto y recurrir a extract_conversation_keys para los eventos de cambio de clave que no puedan verificarse. Esta ruta omite la comprobación de firma y recupera la clave de conversación descifrándola con tu clave de identidad. El modelo de seguridad se mantiene porque:
  • Solo el material de clave que fue cifrado con tu clave de identidad puede recuperarse—un tercero no puede inyectar una clave que puedas leer
  • Cada mensaje sigue verificándose por firma contra su propio remitente, por lo que la autoría de los mensajes no se ve afectada
Mantén primero la ruta verificada: usa decrypt_events (que también alimenta la caché de claves del SDK cuando set_cache_keys(true) está habilitado), y recurre a extract_conversation_keys solo para los eventos de cambio de clave que rechace.

Lista de verificación

  1. Genera el ID con prefijo g con POST /2/chat/conversations/group/initialize
  2. prepare_group_create con todos los miembros; POST los envoltorios de clave de los participantes y ambas firmas de acción a POST /2/chat/conversations/group
  3. Guarda en caché la clave en bruto + versión; actualiza en eventos de cambio de clave
  4. En cambios de membresía, prepare_group_members_change (dos firmas) → POST /2/chat/conversations/{id}/members
  5. Descifra los metadatos del grupo con decrypt cuando los campos sean texto cifrado
  6. Envía/recibe con los mismos patrones que 1:1