# 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:

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](https://app.kinescope.io) em **Configurações → Tokens de API**. Veja mais sobre autorização nas [regras gerais da API](https://docs-br.kinescope.com/developer-guides/api-general-rules/).

```bash
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:

```go
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:**

```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):

```bash
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:**

```json
{
  "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:**

```bash
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:**

```bash
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:**

```bash
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:

```go
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:**
```json
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "key-2024-12-25"
}
```

**Payload:**
```json
{
  "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:
   ```bash
   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:

```go
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](https://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](https://docs-br.kinescope.com/live-streams/live-stream-guide/)** — configurando streams no Kinescope
2. **[Regras gerais da API](https://docs-br.kinescope.com/developer-guides/api-general-rules/)** — autorização e formato de solicitação
3. **[Backend de autorização](https://docs-br.kinescope.com/developer-guides/authorization-backend/)** — 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!

