Chaves e credenciais
O SlotBattle tem quatro credenciais. Elas não compartilham código, armazenamento nem modos de falha, para que adicionar autenticação a uma rota nova não escolha a errada por proximidade.
| Credencial | Quem guarda | Por onde trafega | Rotacionável |
|---|---|---|---|
| Chave de API do tenant | Backend do seu casino | Authorization: Bearer | Emitir + revogar |
| Sessão de console | Browser de um operador | Cookie HttpOnly | Expiração + logout |
| Token de viewer | Browser de um espectador | Subprotocolo do WebSocket | Chave de assinatura, com janela |
| Segredo de callback do gravador | O gravador | HMAC sobre o corpo da requisição | Redeploy |
1. Chave de API do tenant
A credencial servidor a servidor, e a que o seu backend usa.
Authorization: Bearer sbk_3f9a1c...
Formato. Prefixo sbk_ seguido de 64 caracteres hex (32 bytes aleatórios).
Armazenamento. Só o hash SHA-256 é persistido, mais os 12 primeiros caracteres
(sbk_ + 8 hex) para exibição no console. O texto puro é mostrado uma vez, na criação. Não há
como exibi-lo de novo: perdê-lo significa emitir uma substituta e revogar a antiga.
Escopos. Cada chave carrega o próprio conjunto, checado por rota:
| Escopo | Concede |
|---|---|
games:read | Ler o catálogo de jogos |
battles:read | Ler batalhas |
battles:write | Abrir e gerenciar batalhas |
bots:write | Sentar bots |
viewer:mint | Emitir tokens de viewer |
demo:mint | Emitir uma sessão de jogo demo. Só avaliação, nunca o fluxo de produção |
bots:write é separado de battles:writeSentar bots gasta as sessões de provedor do próprio casino, o que é um ato diferente de abrir uma batalha. Uma chave que só abre batalhas não consegue enchê-las de bots em silêncio. Emita o conjunto mais estreito que funciona.
Emissão. Pelo console (Casino → Chaves de API), ou pelo seu host, se a sua conta não
carrega apikeys.write. A revogação é imediata.
O tenant é derivado da chave, nunca enviado junto. Veja Tenancy.
2. Sessão de console
A credencial do console admin.
É um cookie HttpOnly com escopo /admin, SameSite=Strict, carregando um token de sessão
assinado. O token nunca aparece num corpo de resposta, e Authorization: Bearer não é aceito
nessa superfície. Um bearer token ao alcance do JavaScript pode ser lido por um XSS e
reapresentado indefinidamente; um cookie que o script não lê é limitado pelo browser.
SameSite=Strict restringe o seu DNSSameSite=Strict raciocina sobre o domínio registrável. O console e a API precisam
compartilhar um: painel.exemplo.com e api.exemplo.com funcionam; painel.exemplo.net e
api.exemplo.com não.
Separados em domínios registráveis distintos, toda requisição autenticada falha em silêncio. O browser não anexa o cookie, nada loga erro, e as requisições voltam não autenticadas. Decida isso antes de comprar o domínio.
Não existe rota de registro. A sua primeira conta de operador é criada para você pela plataforma. Segundos fatores opcionais, TOTP com códigos de recuperação e magic links por e-mail, ficam por cima.
3. Token de viewer
Curto, com escopo de batalha, e a única credencial que chega a um browser não confiável.
O que é. Um JWT assinado com Ed25519, audiência slotbattle-ws, com escopo de uma batalha,
válido por 15 minutos.
Como trafega. Não na URL, mas no header de subprotocolo do WebSocket:
Sec-WebSocket-Protocol: slotbattle.jwt, <token>
Um token em query string cai em log de acesso, log de proxy e histórico do browser. O subprotocolo é a única forma alcançável pelo browser de enviar uma credencial no handshake de WebSocket, já que browsers não conseguem definir headers arbitrários ali.
Como conseguir um. Criar uma batalha e adicionar um assento retornam um na resposta. Se
expirou, o que acontece num lobby que ficou aberto por vinte minutos, emita um novo com
POST /battles/{id}/viewer-tokens, que custa viewer:mint.
Rotacionando a chave de assinatura
Um token de viewer vive 15 minutos e já está no browser de todo mundo que está assistindo. Trocar a chave de uma vez invalida todos eles ao mesmo tempo, derrubando todo espectador de toda batalha em andamento.
A rotação, portanto, nomeia uma chave nova e deixa a anterior verificando até se aposentar:
O kid no header de cada token é o que permite a um verificador segurar as duas chaves. Uma
janela de aposentadoria menor que o tempo de vida de um token é recusada, porque deixaria a pé
tokens ainda válidos.
Exatamente uma chave fica ativa por vez, garantido por uma restrição no banco e não por lógica de serviço que duas rotações concorrentes poderiam correr.
A rotação é uma operação de plataforma, só para super-usuário: uma chave assina para todo casino, então não é recurso de nenhum casino em particular.
A variável de ambiente da chave de assinatura é um valor de bootstrap. Vale só enquanto a tabela de chaves está vazia. Uma vez que exista uma chave, a rotação é a única forma de trocá-la, e editar a variável de ambiente não tem efeito.
4. Segredo de callback do gravador
Interno. O gravador assina o callback terminal de cada assento com HMAC sobre o corpo cru da requisição, e a assinatura é a única credencial daquela rota; não há auth de tenant nela.
Você nunca lida com esta. Ela vive entre o control plane da plataforma e os gravadores dela, e
está listada aqui para que recorder numa linha de log não seja confundido com uma credencial
que você deveria ter recebido.
Todo ato com credencial é atribuído
Emitir uma chave, revogar uma chave e rotacionar a chave de assinatura registram quem fez, como o endereço do ator na época, capturado em vez de referenciado.
Uma chave estrangeira para a tabela de usuários faria cascade ou viraria nula quando aquele
usuário fosse apagado, apagando o registro. O ator sempre vem da sessão autenticada, nunca do
corpo da requisição; nomear um no payload é um 400.
Uma chave emitida fora do console não tem usuário logado e reporta CLI / unknown em vez de
vazio, porque célula vazia parece falha de renderização.
Orientações práticas
Dê a cada consumidor a própria chave. Uma chave por serviço de backend, com escopo do que aquele serviço faz. Revogar uma chave compartilhada derruba todos os consumidores de uma vez.
Nunca deixe uma chave de API chegar a um browser. É uma credencial servidor a servidor com raio de dano do tamanho do casino. O tutorial passa toda chamada por handlers no servidor justamente por isso. Veja Assista a uma batalha ao vivo.
Emita tokens de viewer por espectador, por batalha. Eles são baratos, curtos e com escopo. Reusar um entre batalhas não é possível, e reusar um entre espectadores descarta a única granularidade de revogação disponível.
Próximo
- Autenticação: a chave de API no fio e as respostas de erro
- WebSocket: o handshake do token de viewer por inteiro
- Chaves de assinatura: rotacionando pelo console