Verificação de identidade
Sua write key pública identifica seu projeto, mas não autentica ninguém: qualquer um pode abrir um console de navegador e enviar eventos como distinct_id: "[email protected]". A verificação de identidade fecha esse buraco — seu backend assina um JWT de vida curta provando que este navegador realmente é este usuário, e o Kilden o verifica em cada evento identificado.
O tráfego anônimo não é afetado: não há identidade a forjar, então eventos anônimos nunca precisam de token.
Como funciona
Seção intitulada “Como funciona”- Nas configurações do projeto você cria um identity secret (separado das suas write keys). Cada secret tem um
kid(key id), e vários podem estar ativos ao mesmo tempo, então a rotação não tem janela de transição. - No login, seu backend assina um JWT com esse secret — HS256, com o id do usuário em
sub. - O SDK envia o token com cada batch de eventos como
Authorization: Bearer <token>. - O pipeline o verifica: assinatura contra um
kidativo,expválido esubigual aodistinct_iddo evento. O resultado é armazenado em cada evento comoverified.
O token
Seção intitulada “O token”Payload de claims:
{ "sub": "user_4821", "iat": 1752192000, "exp": 1752195600, "traits": { "plan": "pro" }}sub— obrigatório. Deve ser igual aodistinct_idque o navegador vai usar (o que você passa paraidentify()).exp— obrigatório. Mantenha-o curto (minutos a horas); o SDK renova automaticamente.kid— obrigatório, no header do JWT (não no payload). Identifica qual identity secret do projeto assinou o token.traits— opcional. Traits assinados, aplicados com verificação do servidor.- Algoritmo: somente HS256. Tokens assinados com qualquer outra coisa (incluindo
none) falham na verificação.
Assinando no seu backend
Seção intitulada “Assinando no seu backend”Os SDKs de servidor trazem um IdentitySigner que
produz este token em três linhas — sem biblioteca de JWT, sem adivinhar o
conjunto de claims, testado byte a byte contra o verificador da plataforma:
import { IdentitySigner } from "@kilden-io/node";
const signer = new IdentitySigner(process.env.KILDEN_IDENTITY_SECRET!, { kid: "k1" });
app.post("/kilden/identity", (req, res) => { const user = req.user; // your auth middleware — never an id from request input res.json({ distinct_id: String(user.id), token: signer.sign(String(user.id), { traits: { plan: user.plan } }), });});$signer = new Kilden\IdentitySigner(getenv('KILDEN_IDENTITY_SECRET'), ['kid' => 'k1']);
$token = $signer->sign($user->id, [ 'traits' => ['plan' => $user->plan],]);A mesma classe existe em Python, Ruby e Go.
Dois atalhos pulam até isso: o kilden/laravel traz uma rota publicável
POST /kilden/identity, e o plugin de WordPress expõe
/wp-json/kilden/v1/identity — ambos atrás da sua auth existente. No
Laravel, @kildenScript no seu layout renderiza o SDK web com o callback
do token já conectado a POST /kilden/identity.
Prefere uma biblioteca de JWT que você já usa? O token é um JWT HS256
padrão: sub (deve ser igual ao id que você passa ao kilden.identify()),
iat, exp (TTLs curtos — uma hora basta), traits opcional, e o header
kid nomeando o secret. Qualquer implementação correta de JWT verifica bem;
os SDKs apenas tornam o certo a coisa fácil.
Conectando o SDK
Seção intitulada “Conectando o SDK”Deixe o SDK gerenciar o ciclo de vida do token — ele renova cerca de um minuto antes do exp e tenta de novo uma vez ao receber 401:
kilden.init('YOUR_WRITE_KEY', { getIdentityToken: async () => { const res = await fetch('/api/kilden-token'); if (!res.ok) return null; return (await res.json()).token; },});
// depois do login:kilden.identify('user_4821');import kilden from "@kilden-io/expo";
kilden.init("YOUR_WRITE_KEY", { getIdentityToken: async () => { const res = await fetch("https://your-backend.example/kilden/identity", { method: "POST", headers: { Authorization: `Bearer ${sessionToken}` }, // o token de sessão do seu app }); if (!res.ok) return null; return (await res.json()).token; },});
// depois do login:kilden.identify("user_4821");Alternativas: passe um token que você já tem no init (identityToken: '...'), por chamada (identify(id, traits, { token })) ou de forma imperativa (setIdentityToken(token)). No logout, reset() o limpa.
O token viaja por batch, no header Authorization: Bearer. Uma exceção documentada, apenas na web: o flush de fim de página pode cair para sendBeacon, que não carrega headers, então o token vai no corpo como identity_token — mesma proteção TLS, verificado em segundo lugar.
Modos de enforcement
Seção intitulada “Modos de enforcement”A verificação é sempre computada — todo evento identificado recebe verified: true/false independentemente do modo. O modo governa apenas o que acontece com mutações de identidade não verificadas ($identify, $set, $set_once):
| Modo | Mutações de identidade não verificadas de usuários identificados |
|---|---|
off |
Aplicadas normalmente |
monitor |
Aplicadas normalmente, mas cada uma é contabilizada para você ver exatamente o que enforce bloquearia |
enforce |
Não aplicadas: não podem criar pessoas, vincular identidades nem escrever traits. A resolução de identidade para eventos identificados não verificados vira somente leitura — mapeamentos existentes continuam atribuindo, mas nada novo é criado |
Como monitor mede precisamente o que enforce bloquearia, o rollout seguro é: instrumente o token → observe o contador de não verificados cair a zero → mude para enforce. A mudança não altera dado nenhum, só o comportamento.
Duas regras valem em todos os modos:
- Eventos nunca são descartados. Uma verificação que falha mantém o evento com
verified: false; ele é excluído dos consumidores sensíveis a confiança (gatilhos de campanha, e leituras do messenger quando mensageria em canais identificados for lançada), mas permanece no seu analytics. - Eventos anônimos sempre passam. Seu
verified: falseé uma convenção (não há nada a verificar), não desconfiança. Eventos server-side enviados com uma secret key sãoverified: true— a secret key é a autenticação.
Traits assinados
Seção intitulada “Traits assinados”Traits dentro do JWT são aplicados como um $set verificado pelo servidor e têm prioridade sobre traits não assinados no mesmo evento. Use-os para valores que o navegador não deveria poder afirmar sobre si mesmo (plano, papel, status da conta). Para fatos que movimentam dinheiro ou mensageria, prefira enviar o próprio evento server-side.
Rotação
Seção intitulada “Rotação”Crie um novo secret (novo kid) nas configurações do projeto, faça o deploy do seu backend assinando com ele e então desative o kid antigo. Vários secrets ativos significam rotação sem downtime; tokens assinados por um kid desativado falham na verificação imediatamente.