Korzen
Bot Protection

Auth0

Bot Protection com Auth0: uma Action pre-user-registration que pergunta antes de o usuário ser criado, e o que ela vê e não vê.

O Auth0 roda uma Action antes de criar um usuário que se cadastra com senha ou com código sem senha (uma conexão Database ou Passwordless), e essa Action pode chamar o Bot Protection e recusar o cadastro. A página de cadastro é do Auth0, no domínio do Auth0, então a Action não tem cookie _kz: a decisão se apoia no IP e no User-Agent.

A tag

Coloque a tag nas suas próprias páginas, onde as pessoas chegam antes de se cadastrar e onde fazem login e pagam, para essas decisões terem o token:

<script src="https://korzen.dev/v1/tag.js" data-site-key="YOUR_SITE_KEY" async></script>

A chamada

A Action. O Auth0 dá a ela 20 segundos no total; a chamada respeita o seu timeout, e qualquer erro deixa o cadastro passar:

// Auth0 Dashboard: Actions, Triggers, pre-user-registration; a new Action.
// Add the secret KORZEN_API_KEY to the Action.
exports.onExecutePreUserRegistration = async (event, api) => {
  let d = null;
  try {
    const res = await fetch("https://korzen.dev/v1/decide", {
      method: "POST",
      headers: { Authorization: `Bearer ${event.secrets.KORZEN_API_KEY}`, "Content-Type": "application/json" },
      body: JSON.stringify({
        ip: event.request.ip,
        user_agent: event.request.user_agent,
        ja4: event.security_context?.ja4 || undefined, // behind Cloudflare only: left out without it
        headers: { "accept-language": event.request.language },
        path: "/signup",
        method: "POST",
      }),
      signal: AbortSignal.timeout(200),
    });
    if (res.ok) d = await res.json();
  } catch {} // fail open
  if (d?.action === "block") {
    api.access.deny("korzen_block", "We could not create your account.");
    return;
  }
  // "challenge": Auth0's own CAPTCHA or MFA, if your plan has them
  if (d?.request_id) api.user.setAppMetadata("korzen_request_id", d.request_id);
};

O Auth0 dá à Action o idioma e o User-Agent do navegador, mas nenhum dos outros headers da requisição, então a chamada encaminha só accept-language: aqui faltam os headers que uma build de navegador envia iguais, que o Bot Protection lê nas chamadas do seu próprio servidor.

Num tenant cujo tráfego passa pelo Cloudflare (os planos Enterprise do Auth0), o evento também tem security_context.ja4: o JA4 do handshake TLS do visitante com a borda do Auth0, na mesma forma que o Bot Protection lê do Cloudflare na frente do seu próprio servidor. A chamada o envia como ja4 quando ele existe; sem ele, fica de fora.

O IP do visitante

event.request.ip é o endereço que chegou ao Auth0, já o do visitante: nada a configurar. Num domínio próprio atrás do seu proxy, veja nas configurações de custom domain do Auth0 como passar o IP do visitante.

As decisões do Auth0 chegam sem o token da tag. Depois que o Bot Protection vê a tag nas suas outras páginas, a falta do token soma um pouco ao score (no_token), nunca o bastante para bot sozinha.

Siga a action

Leia só a action. Em block, responda com o mesmo erro que a ação mostra quando falha por qualquer outro motivo, para o bot não aprender nada. Em challenge, use a verificação que você já tem (um CAPTCHA, um código por email ou telefone); sem nenhuma, siga em frente. A conta começa em monitor mode, em que a action é sempre allow: nada muda para os visitantes até você ligar o block mode.

Guarde o request_id

Toda resposta tem um request_id. Guarde-o junto do que a ação criou, numa coluna da conta ou do pedido, ou numa linha de log com o id deles. Com ele, você acha a decisão quando falar com a gente e descobre depois qual resposta deixou passar uma conta falsa.

Teste na sua máquina

Use o seu tenant de desenvolvimento. No editor da Action, o botão Test roda a Action com um evento de exemplo; depois cadastre-se na sua página de login, e a decisão aparece na página Decisões do painel em /signup. Confira o fail open com um secret KORZEN_API_KEY errado: o cadastro passa.

Erros comuns

  • Cadastros sociais. Google, GitHub e afins não rodam o trigger pre-user-registration; uma Action post-login pode perguntar ao Bot Protection sobre eles no primeiro login.
  • Chamar /v1/decide do navegador. A API key ficaria exposta para todo visitante; a chamada sai do seu servidor.
  • Sem timeout, ou um erro que trava o cadastro. Se a resposta não for 200, ou não chegar a tempo, deixe o visitante passar.