Autenticação JWT para Chat de Stream
A autenticação JWT permite autorizar automaticamente usuários no chat de stream e controlar o acesso do seu servidor. Isso é especialmente útil se você quiser integrar o chat com seu sistema de gerenciamento de usuários.
Para quem é este artigo
- Desenvolvedores de plataforma — precisam integrar o chat de stream com um sistema de autenticação
- Administradores de sistema — precisam controlar o acesso ao chat de stream
- Desenvolvedores backend — precisam configurar a autorização segura de usuários
Quando você precisa de autenticação JWT para o chat
Use a autenticação JWT se:
- Controle de acesso é necessário — você quer decidir no seu servidor quem pode escrever no chat
- Integração com seu sistema — você precisa vincular usuários do chat com seu sistema de autenticação
- Autorização automática — os usuários devem ser autorizados sem passos adicionais
- Vinculação com sistema de contas — você precisa rastrear qual dos seus usuários está escrevendo no chat
Como o JWT funciona no chat (5 passos)
A autenticação JWT usa criptografia assimétrica (RSA) para transmissão segura de dados do usuário:
- Você cria um par de chaves (privada e pública) no seu servidor
- A chave pública é salva no Kinescope via API (a chave privada fica apenas com você)
- Seu servidor cria um token JWT com dados do usuário e o assina com a chave privada
- O token é passado na URL do chat como parâmetro
token - O Kinescope verifica a assinatura com a chave pública e autoriza o usuário
Como habilitar a autenticação JWT
A autenticação é configurada individualmente para cada stream via API do Kinescope. Passe o parâmetro chat_jwt_required: true para habilitá-la:
Importante: O token de API no cabeçalho
Authorization: Bearerdeve estar no formato UUID. Você pode obter um token no Dashboard do Kinescope em Configurações → Tokens de API. Veja mais sobre autorização nas regras gerais da API .
curl --location --request PUT 'https://api.kinescope.io/v2/live/events/{{event_id}}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer seu_token_de_api_aqui' \
--data '{
"chat_jwt_required": true
}'
Após a habilitação, os usuários serão autorizados automaticamente ao seguir um link com token:
https://kinescope.io/chat/{{event_id}}?token={{jwt}}
Agora vamos ver como configurar tudo do zero.
Configuração: passo 1 — gerando chaves
A autenticação JWT usa criptografia RSA assimétrica, que requer um par de chaves:
- Chave privada — fica no seu servidor, usada para assinar tokens JWT
- Chave pública — transmitida ao Kinescope via API, usada para verificar assinaturas de tokens
O que é JWK?
JWK (JSON Web Key) é um formato padronizado para representar chaves criptográficas (RFC 7517). Ele permite a troca segura de chaves entre sistemas:
- Segurança — a chave privada nunca sai do seu servidor
- Rotação de chaves — substitua facilmente as chaves fazendo upload de uma nova chave pública
- Revogação de acesso — se uma chave for comprometida, exclua imediatamente a chave pública do Kinescope
- Padronização — JWK é suportado pela maioria das bibliotecas e sistemas
Exemplo de geração de JWK
Aqui está como parece a geração de um par de chaves:
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/json"
"time"
"github.com/go-jose/go-jose/v3"
)
type JWK struct {
Kty string `json:"kty"` // tipo de chave (RSA)
Kid string `json:"kid"` // identificador da chave (único)
Use string `json:"use"` // propósito (sig para assinatura)
Alg string `json:"alg"` // algoritmo (RS256)
N string `json:"n"` // módulo da chave RSA (codificado em base64url)
E string `json:"e"` // expoente (geralmente "AQAB")
}
// Gerar par de chaves RSA de 2048 bits
func generateRSAKeyPair() (*rsa.PrivateKey, *JWK, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}
// Gerar ID de Chave único (kid)
kid := "key-" + time.Now().Format("2006-01-02")
// Construir chave pública em formato JWK
publicKeyJWK := &JWK{
Kty: "RSA",
Kid: kid,
Use: "sig", // propósito - assinatura
Alg: "RS256", // algoritmo - RSA com SHA-256
N: base64.RawURLEncoding.EncodeToString(privateKey.PublicKey.N.Bytes()),
E: base64.RawURLEncoding.EncodeToString([]byte{1, 0, 1}), // 65537 = AQAB
}
return privateKey, publicKeyJWK, nil
}
// Salvar chave privada no formato PEM
func savePrivateKey(key *rsa.PrivateKey) ([]byte, error) {
return x509.MarshalPKCS8PrivateKey(key)
}
Exemplo de JWK público pronto em JSON:
{
"kty": "RSA",
"kid": "key-2024-12-25",
"use": "sig",
"alg": "RS256",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbwE...",
"e": "AQAB"
}
Descrição dos campos:
kty— tipo de chave (RSA)kid— identificador da chave (único no seu sistema)use— propósito da chave (sigpara assinatura)alg— algoritmo de assinatura (RS256para RSA com SHA-256)n— módulo da chave RSA (codificado em base64url)e— expoente da chave RSA (geralmenteAQAB, que significa 65537)
Salvando a chave pública no Kinescope
Após gerar o JWK, salve a parte pública da chave no Kinescope via API. Certifique-se de passar todos os parâmetros: kty, e, use, kid, alg, n e expires_at (data de expiração da chave no formato ISO 8601):
curl --location 'https://api.kinescope.io/v1/jwk' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer seu_token_de_api_aqui' \
--data '{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "key-2024-12-25",
"alg": "RS256",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbwE...",
"expires_at": "2026-12-31T23:59:59Z"
}'
Exemplo de resposta bem-sucedida:
{
"id": "jwk_abc123def456",
"kty": "RSA",
"kid": "key-2024-12-25",
"created_at": "2024-12-25T10:00:00Z",
"expires_at": "2026-12-31T23:59:59Z"
}
Gerenciamento de chaves
Ver todas as chaves ativas:
curl --location 'https://api.kinescope.io/v1/jwk' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer seu_token_de_api_aqui'
Obter dados de uma chave específica:
curl --location 'https://api.kinescope.io/v1/jwk/{{jwk_id}}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer seu_token_de_api_aqui'
Excluir uma chave:
curl --location --request DELETE 'https://api.kinescope.io/v1/jwk/{{jwk_id}}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer seu_token_de_api_aqui'
Configuração: passo 2 — gerando um token JWT
Crie um token JWT (JSON Web Token, RFC 7519) com os campos obrigatórios e assine-o com sua chave privada.
Campos obrigatórios
aud(audience) — valor"chat"(obrigatório). O Kinescope verifica que o token é destinado ao chat.user_id— identificador único do usuário no seu sistema. Usado para identificação no chat.username— nome de usuário para exibição no chat. Será mostrado ao lado das mensagens.event_id— ID do stream (obrigatório). Pode ser encontrado no seu painel ou no link do stream.
Importante:
event_idé obrigatório para incorporação do chat — o chat pode ser incorporado em uma página sem autenticação JWT, mas ao usar JWT,event_idé necessário para vincular o token a um stream específico.
Campos JWT padrão (recomendados)
exp(expiration) — tempo de expiração do token (timestamp Unix). Recomenda-se definir um tempo de vida curto (por exemplo, 1 hora).nbf(not before) — tempo antes do qual o token é inválido (timestamp Unix). Útil para tokens que devem se tornar ativos no futuro.iat(issued at) — tempo de criação do token (timestamp Unix). Ajuda a rastrear a idade do token.
Todos os campos JWT padrão serão verificados pelo sistema do Kinescope ao validar o token.
Exemplo de geração de JWT
Aqui está como parece a geração e assinatura do JWT:
package main
import (
"crypto/rsa"
"time"
"github.com/golang-jwt/jwt/v5"
)
type ChatClaims struct {
UserID string `json:"user_id"`
Username string `json:"username"`
EventID string `json:"event_id"`
jwt.RegisteredClaims
}
// Gerar token JWT
func generateJWT(privateKey *rsa.PrivateKey, kid string, userID, username, eventID string) (string, error) {
now := time.Now()
claims := ChatClaims{
UserID: userID,
Username: username,
EventID: eventID,
RegisteredClaims: jwt.RegisteredClaims{
Audience: []string{"chat"}, // deve ser "chat"
IssuedAt: jwt.NewNumericDate(now),
ExpiresAt: jwt.NewNumericDate(now.Add(1 * time.Hour)), // padrão 1 hora
},
}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
token.Header["kid"] = kid // ID da chave
return token.SignedString(privateKey)
}
// Exemplo de uso
func main() {
privateKey, publicKeyJWK, err := generateRSAKeyPair()
if err != nil {
panic(err)
}
kid := publicKeyJWK.Kid
jwtToken, err := generateJWT(
privateKey,
kid,
"user-12345", // ID do usuário
"João Silva", // Nome de usuário
"event-abc-123", // ID do stream
)
if err != nil {
panic(err)
}
println("Token JWT:", jwtToken)
}
Para desenvolvedores: Em uma implementação real, use bibliotecas para geração de JWT:
- Node.js:
node-jsonwebtoken(jwt.sign()),jose(new SignJWT().setProtectedHeader().sign())- Browser: Web Crypto API (
crypto.subtle.sign())- Python:
PyJWT(jwt.encode())- Go:
github.com/golang-jwt/jwt/v5(jwt.NewWithClaims().SignedString())
Estrutura do token JWT
Um JWT consiste em três partes separadas por pontos: header.payload.signature
Header:
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-2024-12-25"
}
Payload:
{
"aud": "chat",
"user_id": "user-12345",
"username": "João Silva",
"event_id": "event-abc-123",
"iat": 1703500800,
"exp": 1703504400
}
Assinatura: A assinatura é criada fazendo hash de base64(header) + "." + base64(payload) usando a chave privada com o algoritmo RS256.
Usando o token
Após gerar o token, passe-o na URL do chat:
https://kinescope.io/chat/event-abc-123?token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleS0yMDI0LTEyLTI1In0...
Pronto! Seus usuários agora podem ser autorizados automaticamente no chat de stream via tokens JWT.
Segurança
Rotação de chaves
É recomendado atualizar regularmente as chaves para melhorar a segurança. O processo de rotação:
- Gere um novo par de chaves (privada e pública)
- Faça upload da nova chave pública para o Kinescope via API (a chave antiga permanecerá ativa)
- Comece a usar a nova chave privada para assinar novos tokens
- Após o período de sobreposição (quando todos os tokens antigos expiram), exclua a chave pública antiga do Kinescope
Ações quando uma chave é comprometida
Se a chave privada foi comprometida (vazamento, suspeita de violação):
- Exclua imediatamente a chave pública do Kinescope via API:
curl --location --request DELETE 'https://api.kinescope.io/v1/jwk/{{jwk_id}}' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer seu_token_de_api_aqui' - Gere um novo par de chaves e faça upload da nova chave pública
- Notifique os usuários de que precisam se re-autorizar (se necessário)
- Verifique os logs para atividade suspeita
Recomendações de segurança
- Tamanho da chave: Use chaves de pelo menos 2048 bits (recomendado para RSA)
- Tempo de vida do token: Defina um tempo de vida curto para o token (1–24 horas). Para sessões de longa duração, use um mecanismo de atualização de token
- Tempo de vida da chave: Defina
expires_atpara chaves públicas (por exemplo, 1–2 anos) e planeje a rotação antes da expiração - Armazenamento da chave privada: Armazene a chave privada em um cofre seguro (por exemplo, Kubernetes secrets, AWS Secrets Manager ou um armazenamento criptografado)
- Monitoramento: Rastreie o uso de chaves e atividades suspeitas
- Algoritmo: Use apenas RS256 (RSA com SHA-256). Outros algoritmos não são suportados
Limitações
- Algoritmos suportados: Apenas RS256 (RSA com SHA-256)
- Tamanho mínimo da chave: 2048 bits
- Número máximo de chaves ativas: Pode haver um limite no nível da conta (verifique com o suporte)
Solução de problemas
Token não aceito pelo sistema
Problema: O usuário não consegue se autorizar, o token é rejeitado.
Possíveis causas e soluções:
Assinatura de token inválida
- Certifique-se de que você está usando a chave privada correta para assinatura
- Verifique se a chave pública está carregada no Kinescope e está ativa
- Certifique-se de que você está usando o algoritmo RS256
Chave expirada
- Verifique o campo
expires_atda chave pública no Kinescope - Se a chave expirou, faça upload de uma nova chave pública
- Verifique o campo
event_idincorreto- Certifique-se de que o
event_idno token corresponde ao ID do stream - Verifique se o stream existe e a autenticação JWT está habilitada para ele
- Importante:
event_idé obrigatório para incorporação do chat — o chat pode ser incorporado sem JWT, mas ao usar JWT, umevent_idválido é obrigatório
- Certifique-se de que o
Token expirado
- Verifique o campo
expno token (tempo de expiração) - Certifique-se de que o relógio do sistema no servidor está sincronizado (NTP)
- Gere novos tokens com tempo de expiração atualizado
- Verifique o campo
Campo
audincorreto- Certifique-se de que o campo
audtem o valor"chat"(estritamente em minúsculas)
- Certifique-se de que o campo
Como verificar a validade do token
Você pode verificar o token localmente antes de enviá-lo ao usuário. Aqui está uma função de verificação de exemplo:
package main
import (
"crypto/rsa"
"errors"
"github.com/golang-jwt/jwt/v5"
)
// Verificar validade do token JWT
func verifyJWT(tokenString string, publicKey *rsa.PublicKey) (*ChatClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &ChatClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, errors.New("algoritmo não suportado")
}
return publicKey, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*ChatClaims); ok && token.Valid {
if !claims.VerifyAudience("chat", true) {
return nil, errors.New("audience inválida")
}
return claims, nil
}
return nil, errors.New("token inválido")
}
Para desenvolvedores: Em uma implementação real, use bibliotecas para verificação de JWT:
- Node.js:
node-jsonwebtoken(jwt.verify()),jose(jwtVerify())- Browser: Web Crypto API (
crypto.subtle.verify())- Python:
PyJWT(jwt.decode())- Go:
github.com/golang-jwt/jwt/v5(jwt.ParseWithClaims())
Ferramentas online:
- jwt.io — decodificação e verificação da estrutura do token (sem verificação de assinatura)
- Verifique a estrutura do payload: todos os campos obrigatórios devem estar presentes
Erros comuns ao gerar chaves
Erro “invalid key format”
- Certifique-se de que você está usando o formato JWK correto (RFC 7517)
- Verifique se todos os campos obrigatórios estão presentes:
kty,e,n,kid,alg,use
Erro “key size too small”
- Use chaves de pelo menos 2048 bits
- Ao gerar:
rsa.GenerateKey(rand.Reader, 2048)
Erro “key expired”
- Verifique o campo
expires_atao fazer upload da chave - Certifique-se de que a data de expiração está no formato ISO 8601:
"2026-12-31T23:59:59Z"
- Verifique o campo
Problemas de incorporação do chat
Problema: O chat não é exibido ou não autoriza o usuário quando incorporado.
Soluções:
- Verifique
event_idno token — ele deve corresponder ao ID do stream ao qual o chat está vinculado - Certifique-se de que a autenticação JWT está habilitada para o stream via API
- Verifique o formato da URL — o token deve ser passado como parâmetro
token:
Exemplo:https://kinescope.io/chat/{{event_id}}?token={{jwt_token}}https://kinescope.io/chat/event-abc-123?token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... - Verifique o console do navegador para erros de JavaScript
Se o problema não for resolvido, entre em contato com o chat de suporte na interface do Kinescope com:
- ID do stream (
event_id) - Exemplo de token (dados sensíveis podem ser mascarados)
- Descrição do problema e etapas de reprodução
Pronto! Agora você pode configurar a autenticação JWT para chat de stream e autorizar automaticamente os usuários.
O que fazer a seguir?
- Guia de transmissões ao vivo — configurando streams no Kinescope
- Regras gerais da API — autorização e formato de solicitação
- Backend de autorização — controle de acesso a vídeos
Ainda tem dúvidas? Escreva para o chat de suporte na interface do Kinescope — nossos especialistas vão ajudar!