Codeigniter

CSRF no CodeIgniter 4: The action you requested is not allowed no AJAX

O primeiro POST do formulário via AJAX grava direitinho e o segundo devolve 403 com The action you requested is not allowed. Não é token errado: é token velho. Com $regenerate = true em app/Config/Security.php, cada requisição válida queima o hash e gera outro, e o seu JavaScript continua mandando o que veio no carregamento da página.

Mande o hash no header e troque ele a cada resposta

Guardo o hash numa meta tag do layout, leio dali na hora do envio e regravo com o valor que o controller devolve:

<!-- na view/layout -->
<meta name="csrf-hash" content="<?= csrf_hash() ?>">

// no JS
const meta = document.querySelector('meta[name="csrf-hash"]');

const r = await fetch('/pedido/salvar', {
  method: 'POST',
  headers: { 'X-CSRF-TOKEN': meta.content, 'Accept': 'application/json' },
  body: new FormData(document.getElementById('form-pedido'))
});

const dados = await r.json();
meta.content = dados.csrf; // hash novo pro próximo POST

No controller, devolva o hash junto com a resposta. Como o CodeIgniter regenera antes de o seu método rodar, o csrf_hash() daqui já é o valor válido para a próxima chamada:

return $this->response->setJSON([
    'ok'   => true,
    'csrf' => csrf_hash(),
]);

O nome do header precisa bater com o Config

Se o header tiver outro nome, o filtro nem enxerga o token. Confira as propriedades em app/Config/Security.php: $headerName (padrão X-CSRF-TOKEN), $tokenName, $regenerate e $redirect. Em API deixe o $redirect em false — senão a falha vira um redirect que o fetch engole e você recebe HTML onde esperava JSON.

Não troque os dois helpers: csrf_token() devolve o nome do campo e csrf_hash() devolve o valor. Quem viaja no header é o hash. Se preferir mandar no corpo, o filtro olha o POST antes do header.

Dá pra matar o sintoma com $regenerate = false: um hash serve a sessão inteira. Funciona, mas você abre mão da proteção contra reenvio do token — em produção prefiro pagar as três linhas de JavaScript.

Post Recentes

json_validate no PHP 8.3: conferir se o JSON é válido sem decodificar

A função json_validate do PHP 8.3 diz se a string é JSON válido sem montar array nem objeto. Serve para…

6 horas atrás

Chave de API fora do Git: .env, getenv() e o que fazer se ela já vazou

Tire a chave de API do código com variável de ambiente, bloqueie o .env no nginx e entenda por que…

14 horas atrás

HPOS no WooCommerce: ativar as tabelas wc_orders e migrar os pedidos

A opção de armazenamento de pedidos travada em posts e a sincronização que nunca termina: como migrar para as tabelas…

24 horas atrás

str_contains no PHP 8: parar de comparar strpos com !== false

Troque strpos e substr por str_contains, str_starts_with e str_ends_with no PHP 8, com o polyfill para quem ainda mantém servidor…

1 dia atrás

Data Patch Magento 2: criar atributo de produto sem InstallData

Copiou um InstallData.php de tutorial antigo e o atributo não apareceu depois do setup:upgrade? Veja a classe de Data Patch…

2 dias atrás

Criar cupom no WooCommerce por código: WC_Coupon com validade e limite

Função pronta para gerar um cupom único por cliente depois do pedido concluído, com WC_Coupon, data de expiração, limite de…

2 dias atrás