Pular navegação

Autenticação JWT para Chat de Stream

Atualizado: 07.04.2026
Abrir como Markdown

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:

  1. Você cria um par de chaves (privada e pública) no seu servidor
  2. A chave pública é salva no Kinescope via API (a chave privada fica apenas com você)
  3. Seu servidor cria um token JWT com dados do usuário e o assina com a chave privada
  4. O token é passado na URL do chat como parâmetro token
  5. O Kinescope verifica a assinatura com a chave pública e autoriza o usuário
Vantagem do esquema assimétrico: A chave privada nunca sai do seu servidor. O Kinescope recebe apenas a chave pública e pode verificar assinaturas, mas não pode criar tokens falsos. Isso é mais seguro do que um esquema simétrico (HS256), onde um segredo compartilhado precisaria ser transmitido ao Kinescope.

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: Bearer deve 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:

  1. Segurança — a chave privada nunca sai do seu servidor
  2. Rotação de chaves — substitua facilmente as chaves fazendo upload de uma nova chave pública
  3. Revogação de acesso — se uma chave for comprometida, exclua imediatamente a chave pública do Kinescope
  4. Padronização — JWK é suportado pela maioria das bibliotecas e sistemas
Por que não uma chave simétrica (HS256)? Com um esquema simétrico, você precisaria transmitir a chave secreta ao Kinescope. Isso cria um risco de comprometimento: se a chave for comprometida no Kinescope, um invasor poderia criar tokens falsos. Com um esquema assimétrico (RS256), mesmo que a chave pública seja comprometida, um invasor não pode criar tokens, pois a chave privada, que fica apenas com você, é necessária para isso.

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 (sig para assinatura)
  • alg — algoritmo de assinatura (RS256 para RSA com SHA-256)
  • n — módulo da chave RSA (codificado em base64url)
  • e — expoente da chave RSA (geralmente AQAB, 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:

  1. Gere um novo par de chaves (privada e pública)
  2. Faça upload da nova chave pública para o Kinescope via API (a chave antiga permanecerá ativa)
  3. Comece a usar a nova chave privada para assinar novos tokens
  4. Após o período de sobreposição (quando todos os tokens antigos expiram), exclua a chave pública antiga do Kinescope
Período de sobreposição: É recomendado manter a chave antiga ativa por um período igual ao tempo de vida máximo do token (por exemplo, se os tokens vivem 24 horas, mantenha a chave antiga por 24 horas após começar a usar a nova).

Ações quando uma chave é comprometida

Se a chave privada foi comprometida (vazamento, suspeita de violação):

  1. 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'
    
  2. Gere um novo par de chaves e faça upload da nova chave pública
  3. Notifique os usuários de que precisam se re-autorizar (se necessário)
  4. Verifique os logs para atividade suspeita
Importante: Após excluir a chave, todos os tokens assinados com essa chave se tornarão inválidos. Os usuários precisarão obter novos tokens.

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_at para 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:

  1. 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
  2. Chave expirada

    • Verifique o campo expires_at da chave pública no Kinescope
    • Se a chave expirou, faça upload de uma nova chave pública
  3. event_id incorreto

    • Certifique-se de que o event_id no 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, um event_id válido é obrigatório
  4. Token expirado

    • Verifique o campo exp no 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
  5. Campo aud incorreto

    • Certifique-se de que o campo aud tem o valor "chat" (estritamente em minúsculas)

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

  1. 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
  2. Erro “key size too small”

    • Use chaves de pelo menos 2048 bits
    • Ao gerar: rsa.GenerateKey(rand.Reader, 2048)
  3. Erro “key expired”

    • Verifique o campo expires_at ao fazer upload da chave
    • Certifique-se de que a data de expiração está no formato ISO 8601: "2026-12-31T23:59:59Z"

Problemas de incorporação do chat

Problema: O chat não é exibido ou não autoriza o usuário quando incorporado.

Soluções:

  1. Verifique event_id no token — ele deve corresponder ao ID do stream ao qual o chat está vinculado
  2. Certifique-se de que a autenticação JWT está habilitada para o stream via API
  3. Verifique o formato da URL — o token deve ser passado como parâmetro token:
    https://kinescope.io/chat/{{event_id}}?token={{jwt_token}}
    
    Exemplo:
    https://kinescope.io/chat/event-abc-123?token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
    
  4. 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?

  1. Guia de transmissões ao vivo — configurando streams no Kinescope
  2. Regras gerais da API — autorização e formato de solicitação
  3. 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!