---
type: how-to
title: Receitas de proxy reverso e o contrato do callback
summary: Ligue a porta de proxy no Traefik ou Caddy, hospede o callback que transforma um passe resolvido no cookie, e proteja o Authelia sem tocar nele.
---

Todo proxy reverso precisa das mesmas duas peças: uma checagem **autorizador** que pergunta ao Caputchin se uma requisição leva um passe válido, e um **callback** na sua origem que transforma um passe resolvido no cookie `cpt_gate`. O [passo a passo do nginx](/docs/proxy-page-gate/set-up) mostra a forma de ponta a ponta; esta página dá os outros proxies, o contrato exato do callback, e um exemplo completo do Authelia. Substitua `YOUR_SITE_KEY` pela sua chave pública em toda parte.

Os endpoints são os mesmos em toda parte:

- **Autorizador**: `GET https://verify.caputchin.com/v1/gate/authz?site=YOUR_SITE_KEY`, com o cabeçalho `Cookie` do visitante encaminhado. `204` significa permitir, `401` significa desafio.
- **Desafio**: redirecione o navegador para `https://verify.caputchin.com/v1/gate/challenge?site=YOUR_SITE_KEY&return=<a URL original>`.

## Traefik

Use um middleware `forwardAuth` para o autorizador. O Traefik encaminha o cabeçalho `Cookie` que chega por padrão. Em um `401` do middleware, redirecione o navegador para o desafio (um middleware de página de erro apontado para uma pequena rota que emite o `302`, ou trate o `401` na sua edge).

```yaml
http:
  middlewares:
    cpt-gate:
      forwardAuth:
        address: "https://verify.caputchin.com/v1/gate/authz?site=YOUR_SITE_KEY"
        # The 401 from forwardAuth is your signal to send the browser to:
        #   https://verify.caputchin.com/v1/gate/challenge?site=YOUR_SITE_KEY&return=<original-url>
  routers:
    portal:
      rule: "Host(`auth.example.com`)"
      middlewares: ["cpt-gate"]
      service: your-app
```

## Caddy

Use `forward_auth` para o autorizador e `handle_errors` para transformar o `401` em um redirecionamento. Isto é um ponto de partida; ajuste a sintaxe das diretivas para a sua versão do Caddy.

```caddy
auth.example.com {
  forward_auth https://verify.caputchin.com {
    uri /v1/gate/authz?site=YOUR_SITE_KEY
    copy_headers Cookie
  }
  handle_errors {
    @challenge expression {http.error.status_code} == 401
    redir @challenge https://verify.caputchin.com/v1/gate/challenge?site=YOUR_SITE_KEY&return={scheme}://{host}{uri} 302
  }
  reverse_proxy your-app:8080
}
```

## O callback

A página de desafio hospedada termina auto-enviando um formulário `POST` para `https://<sua-origem>/__cpt/callback` com dois campos no **corpo**: `cpt_gate` (o passe) e `to` (para onde enviar o visitante). Adicione esta única rota à sua origem (ou como uma location dedicada no proxy). Ela deve:

1. Ler `cpt_gate` e `to` do **corpo** do POST, nunca da URL (um passe em uma URL vaza para logs e referenciadores).
2. Confirmar que `to` está na sua própria origem, e rejeitar qualquer outra coisa, para que o callback não possa ser transformado em um open redirect.
3. Definir o cookie com os atributos abaixo.
4. Redirecionar (`303`) para `to`.

```js
// Any tiny handler on your origin works. Express shown; ~15 lines.
app.post("/__cpt/callback", express.urlencoded({ extended: false }), (req, res) => {
  const pass = String(req.body.cpt_gate || "");
  const to = String(req.body.to || "/");
  const target = new URL(to, `https://${req.headers.host}`);
  if (target.host !== req.headers.host) return res.status(400).end(); // same-origin only
  res.setHeader(
    "Set-Cookie",
    `cpt_gate=${pass}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=1800`
  );
  res.redirect(303, target.pathname + target.search);
});
```

Os atributos do cookie são todo o modelo de segurança. Como o passe não está amarrado a um dispositivo, `HttpOnly` (bloqueia o roubo por script), `Secure` (só HTTPS), `SameSite=Lax`, e um `Max-Age` curto (a casar com a sua TTL de liberação) são o que o protege. Além disso: não registre o valor `cpt_gate` nos seus access logs, e mantenha `Referrer-Policy: no-referrer` no callback para que o passe nunca viaje de carona em um cabeçalho referenciador.

## Exemplo trabalhado: Authelia

O portal de login do Authelia é uma app mono-página compilada sem lugar para incrustar o widget e sem hook de plugin, então a porta é o jeito de protegê-lo. O Authelia já fica atrás de um proxy reverso (é assim que o próprio ForwardAuth dele funciona), e esse proxy é onde a porta vai. O Authelia em si fica completamente sem modificação.

Ponha a porta no vhost do portal (por exemplo `auth.example.com`):

- **Ponha porta** no HTML do portal e no endpoint de login de primeiro fator (`/api/firstfactor`).
- **Exclua** o endpoint verify do próprio ForwardAuth do Authelia (`/api/verify`), que o proxy chama para toda requisição upstream protegida. Pôr porta nele quebraria toda app protegida atrás do Authelia.
- **Exclua** os health checks e os assets estáticos de que a própria página do desafio precisa.
- **Adicione** a rota `/__cpt/callback` como acima.

A porta mantém os bots fora do portal; a Regulation embutida do Authelia (limite de retentativas e banimento) ainda limita as retentativas de credenciais de quem passa, então as duas camadas se empilham. A porta protege só o portal interativo (a UI de login e consentimento); ela não põe porta, e não deve, nos endpoints de token não interativos.

## Veja também

- [Configure a porta de proxy](/docs/proxy-page-gate/set-up): o passo a passo do nginx e o rollout com modo-prévia-primeiro.
- [Visão geral](/docs/proxy-page-gate/overview): o conceito e o cookie de liberação.
- [Estatísticas](/docs/proxy-page-gate/statistics): confirme a ligação observando desafio contra passagem direta.
