Encerrando conexões de membros
A autorização de canal controla as assinaturas, mas não atribui uma identidade no nível da conexão. Sem essa identidade, desconectar o usuário em outro lugar não fecha um socket existente nem remove suas assinaturas de canal.
Chame signin() para atribuir à conexão um member_id do seu backend. A operação de desconexão pode então fechar todas as conexões que o membro mantém no app.
Use esse fluxo após um sign-out remoto, revogação de token, banimento, alteração de senha ou remoção de acesso ao espaço de trabalho.
1. Faça o sign-in da conexão
Aponte o cliente para um endpoint no seu próprio backend e chame signin() uma 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}")A identidade pertence à conexão. Chame signin() uma vez; o cliente faz sign-in novamente após cada reconexão.
O sign-in não autoriza assinaturas de canal. Canais privados e de presença ainda chamam seu endpoint de autorização de canal. Uma conexão sem identidade de membro pode assinar qualquer canal que esse endpoint aprove. Veja Autorizando canais.
2. Assine a identidade no seu backend
O cliente envia o ID da conexão em uma solicitação POST:
Exemplo de código
{ "connection_id": "26896.319537" }Seu endpoint responde com a identidade como uma JSON string, mais uma assinatura sobre essa string exata:
Exemplo de código
{
"auth": "your-app-key:8f9a…",
"member_data": "{\"member_id\":\"u_42\",\"member_info\":{\"name\":\"Ada\"}}"
}A string a ser assinada é <connection_id>::member::<member_data>, com dois dois-pontos de cada lado de member. Aplique HMAC-SHA256 com o app secret, codifique em hexadecimal e prefixe a app key:
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];
}Assine a string member_data exata que você retorna. Re-serializar o objeto pode alterar seus bytes e invalidar a assinatura.
member_id é o valor visado pela operação de desconexão. Ele aceita até 128 caracteres seguros para URL, incluindo + : @ . _ -, mas não / ? # % nem espaços em branco. Se o seu identificador contiver caracteres não suportados, mapeie-o para um valor seguro e estável antes de assinar. O edge rejeita um member ID inválido, deixando a conexão sem uma identidade que a operação de desconexão possa visar.
member_info é opcional. No sign-in de conexão, ele é retornado para aquele cliente em vez de ser transmitido a um canal de presença.
A identidade também pode conter um array watchlist de member ids. Em apps com watchlist_events habilitado, a conexão é notificada quando esses membros ficam online ou offline; veja Eventos de watchlist.
A string assinada aqui é deliberadamente diferente da string que uma assinatura de presença assina, de modo que uma autorização de presença nunca pode ser reutilizada para reivindicar uma identidade, mesmo que ambos os payloads se chamem member_data.
3. Desconecte o membro
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"A operação fecha todas as conexões com sign-in desse membro no app, incluindo outras abas e dispositivos. Ela não fecha conexões anônimas nem conexões atribuídas a outro membro.
O que o cliente vê
A conexão é fechada com o código 4009 e não reconecta automaticamente:
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()
}Exiba um estado de desconectado quando a autenticação terminar. Chamar bird.connect() inicia uma nova conexão que faz sign-in pelo seu endpoint, então reconecte somente após o estado de autorização do membro mudar.
Uma falha de sign-in não fecha o socket. O cliente reporta a falha separadamente e deixa a conexão sem identidade de membro. Após uma reconexão, o cliente reporta isso por meio de signin_error porque a promise original signin() já foi resolvida.
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}")
}A conexão ainda pode receber eventos de canais autorizados, mas operações de member-event e de desconexão não podem visá-la. No cliente de navegador, bird.signedInMember é null nesse estado.
Impedir a reconexão
A operação de desconexão fecha as conexões atuais sem criar um bloqueio persistente. O mesmo cliente pode se conectar novamente.
Revogue a sessão ou registre o banimento antes de desconectar o membro. Seu endpoint de autorização de membro pode então retornar 403 Forbidden se o cliente reconectar.
Próximos passos
- Autorizando canais aborda a outra assinatura que seu backend calcula, para assinaturas de canais privados e de presença.
- Desconectar um membro é a referência completa de API para a solicitação.
- Enviando eventos para um membro é a outra operação endereçada a membros.
- Canais de presença explicam por que um membro pode manter várias conexões.
Recursos relacionados
Continue com a documentação, guias e exemplos sobre este tópico. Os recursos estão em inglês.
Explore a funcionalidadeRealtimeSiga o percurso de aprendizagemBuild your first integrationGuia de implementaçãoSend your first realtime event
Experimente na prática e obtenha um resumo de implementação