Cerrar conexiones de un miembro
La autorización de canales controla las suscripciones, pero no asigna una identidad a nivel de conexión. Sin esa identidad, cerrar sesión en otro lugar no cierra un socket existente ni elimina sus suscripciones a canales.
Llama a signin() para asignar a la conexión un member_id desde tu backend. La operación de desconexión puede entonces cerrar todas las conexiones que ese miembro tenga en la app.
Usa este flujo después de un cierre de sesión remoto, una revocación de token, un bloqueo, un cambio de contraseña o la eliminación de un puesto en el espacio de trabajo.
1. Inicia sesión en la conexión
Apunta el cliente a un endpoint en tu propio backend y llama a signin() una vez:
import { BirdRealtime } from "@messagebird/realtime";
const bird = new BirdRealtime({
appKey: "your-app-key",
region: "us1",
memberAuthEndpoint: "/bird/auth/member",
});
const member = await bird.signin();
console.log("signed in as", member.member_id);import BirdRealtime
let bird = BirdRealtime(options: .init(
appKey: "your-app-key",
region: "us1",
memberAuthEndpoint: URL(string: "https://your-backend.example.com/bird/auth/member")
))
let member = try await bird.signin()
print("signed in as", member.memberId)import com.bird.realtime.BirdRealtime
import com.bird.realtime.BirdRealtimeOptions
val bird = BirdRealtime(
BirdRealtimeOptions(
appKey = "your-app-key",
region = "us1",
memberAuthEndpoint = "https://your-backend.example.com/bird/auth/member",
)
)
val member = bird.signin() // suspending
println("signed in as ${member.memberId}")La identidad pertenece a la conexión. Llama a signin() una vez; el cliente vuelve a iniciar sesión después de cada reconexión.
Iniciar sesión no autoriza suscripciones a canales. Los canales privados y de presencia siguen llamando a tu endpoint de autorización de canales. Una conexión sin identidad de miembro puede suscribirse a cualquier canal que ese endpoint apruebe. Consulta Autorización de canales.
2. Firma la identidad desde tu backend
El cliente envía el ID de conexión en una solicitud POST:
Ejemplo de código
{ "connection_id": "26896.319537" }Tu endpoint responde con la identidad como JSON string, más una firma sobre esa cadena exacta:
Ejemplo de código
{
"auth": "your-app-key:8f9a…",
"member_data": "{\"member_id\":\"u_42\",\"member_info\":{\"name\":\"Ada\"}}"
}La cadena a firmar es <connection_id>::member::<member_data>, con dos signos de dos puntos a cada lado de member. Aplica HMAC-SHA256 con el secreto de la app, codifica en hexadecimal y añade como prefijo la clave de la app:
import { createHmac } from "node:crypto";
app.post("/bird/auth/member", (req, res) => {
const { connection_id } = req.body;
// Your own decision: who is this caller, and may they connect at all?
const user = getUserFromSession(req);
if (!user) return res.sendStatus(403);
const memberData = JSON.stringify({
member_id: user.id,
member_info: { name: user.name },
});
const sig = createHmac("sha256", process.env.BIRD_REALTIME_SECRET)
.update(`${connection_id}::member::${memberData}`)
.digest("hex");
res.json({ auth: `${process.env.BIRD_REALTIME_KEY}:${sig}`, member_data: memberData });
});import hmac, hashlib, json, os
def sign_in(connection_id: str, user) -> dict:
key = os.environ["BIRD_REALTIME_KEY"]
secret = os.environ["BIRD_REALTIME_SECRET"].encode()
member_data = json.dumps({"member_id": user.id, "member_info": {"name": user.name}})
to_sign = f"{connection_id}::member::{member_data}"
sig = hmac.new(secret, to_sign.encode(), hashlib.sha256).hexdigest()
return {"auth": f"{key}:{sig}", "member_data": member_data}func signIn(connectionID string, user User) (map[string]string, error) {
key := os.Getenv("BIRD_REALTIME_KEY")
secret := []byte(os.Getenv("BIRD_REALTIME_SECRET"))
memberData, err := json.Marshal(map[string]any{
"member_id": user.ID,
"member_info": map[string]string{"name": user.Name},
})
if err != nil {
return nil, err
}
mac := hmac.New(sha256.New, secret)
mac.Write([]byte(connectionID + "::member::" + string(memberData)))
return map[string]string{
"auth": key + ":" + hex.EncodeToString(mac.Sum(nil)),
"member_data": string(memberData),
}, nil
}function signIn(string $connectionId, User $user): array
{
$key = getenv('BIRD_REALTIME_KEY');
$secret = getenv('BIRD_REALTIME_SECRET');
$memberData = json_encode(['member_id' => $user->id, 'member_info' => ['name' => $user->name]]);
$sig = hash_hmac('sha256', "{$connectionId}::member::{$memberData}", $secret);
return ['auth' => "{$key}:{$sig}", 'member_data' => $memberData];
}Firma la cadena member_data exacta que devuelves. Volver a serializar el objeto puede cambiar sus bytes e invalidar la firma.
member_id es el valor al que apunta la operación de desconexión. Acepta hasta 128 caracteres seguros para URL, incluidos + : @ . _ -, pero no / ? # % ni espacios en blanco. Si tu identificador incluye caracteres no admitidos, conviértelo a un valor seguro y estable antes de firmar. El edge rechaza un member ID no válido y deja la conexión sin una identidad que la operación de desconexión pueda apuntar.
member_info es opcional. En el inicio de sesión de la conexión, se devuelve a ese cliente en lugar de transmitirse a un canal de presencia.
La identidad también puede incluir un array watchlist de member ids. En apps con watchlist_events habilitado, la conexión recibe notificaciones cuando esos miembros se conectan o desconectan; consulta Eventos de watchlist.
La cadena que se firma aquí es deliberadamente distinta de la que firma una suscripción de presencia, de modo que una autorización de presencia nunca pueda reutilizarse para reclamar una identidad, aunque ambos payloads se llamen member_data.
3. Desconecta al miembro
await bird.realtime.members.disconnect("rap_01krdgeqcxet5s7t44vh8rt9mg", "u_42");client.realtime.members.disconnect("rap_01krdgeqcxet5s7t44vh8rt9mg", "u_42")if err := client.Realtime.Members.Disconnect(context.Background(), "rap_01krdgeqcxet5s7t44vh8rt9mg", "u_42"); err != nil {
log.Fatal(err)
}$bird->realtime->members->disconnect('rap_01krdgeqcxet5s7t44vh8rt9mg', 'u_42');curl -X POST \
https://us1.platform.bird.com/v1/realtime/apps/rap_01krdgeqcxet5s7t44vh8rt9mg/members/u_42/disconnect \
-H "Authorization: Bearer $BIRD_API_KEY" \
-H "X-Realtime-Key: $BIRD_REALTIME_KEY" \
-H "X-Realtime-Secret: $BIRD_REALTIME_SECRET"La operación cierra todas las conexiones con sesión iniciada de ese miembro en la app, incluidas otras pestañas y dispositivos. No cierra conexiones anónimas ni conexiones asignadas a otro miembro.
Lo que ve el cliente
La conexión se cierra con el código 4009 y no se reconecta automáticamente:
bird.connection.bind("error", (e) => {
if (e.code === 4009) showSignedOutScreen();
});bird.onError { error in
if error.code == 4009 { showSignedOutScreen() }
}bird.onError { error ->
if (error.code == 4009) showSignedOutScreen()
}Muestra un estado de sesión cerrada cuando la autenticación haya terminado. Llamar a bird.connect() inicia una nueva conexión que se autentica a través de tu endpoint, así que reconecta solo después de que cambie el estado de autorización del miembro.
Un fallo en el inicio de sesión no cierra el socket. El cliente reporta el fallo por separado y deja la conexión sin identidad de miembro. Tras una reconexión, el cliente lo reporta a través de signin_error porque la promise signin() original ya se resolvió.
bird.connection.bind("signin_error", (e) => {
console.warn("connection has no identity:", e.message);
});bird.onSigninError { error in
print("connection has no identity:", error.message)
}bird.onSigninError { error ->
println("connection has no identity: ${error.message}")
}La conexión aún puede recibir eventos de canales autorizados, pero las operaciones de eventos de miembro y de desconexión no pueden apuntarla. En el cliente de navegador, bird.signedInMember es null en este estado.
Evitar la reconexión
La operación de desconexión cierra las conexiones actuales sin crear un bloqueo persistente. El mismo cliente puede conectarse de nuevo.
Revoca la sesión o registra el bloqueo antes de desconectar al miembro. Tu endpoint de autorización de miembro puede entonces devolver 403 Forbidden si el cliente se reconecta.
Próximos pasos
- Autorización de canales cubre la otra firma que tu backend calcula, para suscripciones privadas y de presencia.
- Desconectar a un miembro es la referencia completa de API para la solicitud.
- Enviar eventos a un miembro es la otra operación dirigida a un miembro.
- Canales de presencia explican por qué un miembro puede tener varias conexiones.
Recursos relacionados
Continúa con la documentación, guías y ejemplos sobre este tema. Los recursos están en inglés.
Explorar la funcionalidadRealtimeSeguir la ruta de aprendizajeBuild your first integrationGuía de implementaciónSend your first realtime event
Prueba el ejercicio y obtén un resumen de implementación